make macro stepper recover from jumps within expansion

original commit: 678fc4d6f894df87c79a4277eb41c46ace1ea9b3
This commit is contained in:
Ryan Culpepper 2012-10-10 19:11:36 -04:00
parent b3dd6bfbae
commit d0712ceee2
6 changed files with 84 additions and 12 deletions

View File

@ -47,6 +47,7 @@
(define-struct track-origin (before after) #:transparent) (define-struct track-origin (before after) #:transparent)
(define-struct local-remark (contents) #:transparent) (define-struct local-remark (contents) #:transparent)
;; contents : (listof (U string syntax)) ;; contents : (listof (U string syntax))
(define-struct local-mess (events) #:transparent)
;; A PrimDeriv is one of ;; A PrimDeriv is one of
(define-struct (prule base) () #:transparent) (define-struct (prule base) () #:transparent)

View File

@ -42,7 +42,7 @@
enter-list exit-list enter-list exit-list
enter-check exit-check enter-check exit-check
local-post exit-local exit-local/expr local-post exit-local exit-local/expr
local-bind enter-bind exit-bind local-bind enter-bind exit-bind exit-local-bind
local-value-result local-value-binding local-value-result local-value-binding
phase-up module-body phase-up module-body
renames-lambda renames-lambda
@ -173,8 +173,9 @@
(#:args e1 rs next) (#:args e1 rs next)
[(enter-macro ! macro-pre-transform (? LocalActions) [(enter-macro ! macro-pre-transform (? LocalActions)
macro-post-transform ! exit-macro) macro-post-transform ! exit-macro)
(make mrule e1 (and next (wderiv-e2 next)) rs $2 (let ([e2 (and next (wderiv-e2 next))])
$3 $4 $5 $6 $7 next)]) (make mrule e1 e2 rs $2
$3 $4 (and $5 (car $5)) $6 $7 next))])
;; Keyword resolution ;; Keyword resolution
(Resolves (Resolves
@ -202,9 +203,9 @@
(make local-lift-require (car $1) (cadr $1) (cddr $1))] (make local-lift-require (car $1) (cadr $1) (cddr $1))]
[(lift-provide) [(lift-provide)
(make local-lift-provide $1)] (make local-lift-provide $1)]
[(local-bind ! rename-list next) [(local-bind ! rename-list exit-local-bind)
(make local-bind $1 $2 $3 #f)] (make local-bind $1 $2 $3 #f)]
[(local-bind rename-list (? BindSyntaxes) next) [(local-bind rename-list (? BindSyntaxes) exit-local-bind)
(make local-bind $1 #f $2 $3)] (make local-bind $1 #f $2 $3)]
[(track-origin) [(track-origin)
(make track-origin (car $1) (cdr $1))] (make track-origin (car $1) (cdr $1))]
@ -224,6 +225,10 @@
before null after #f mafter before null after #f mafter
(make p:stop mafter mafter null #f)) (make p:stop mafter mafter null #f))
#f after #f))] #f after #f))]
[(local-mess)
;; Represents subsequence of event stream incoherent due to
;; jump (eg, macro catches exn raised from within local-expand).
(make local-mess $1)]
;; -- Not really local actions, but can occur during evaluation ;; -- Not really local actions, but can occur during evaluation
;; called 'expand' (not 'local-expand') within transformer ;; called 'expand' (not 'local-expand') within transformer
[(start (? EE)) #f] [(start (? EE)) #f]

View File

@ -15,6 +15,7 @@
EOF ; . EOF ; .
enter-bind ; . enter-bind ; .
exit-bind ; . exit-bind ; .
exit-local-bind ; .
IMPOSSIBLE ; useful for error-handling clauses that have no IMPOSSIBLE ; useful for error-handling clauses that have no
; NoError counterpart ; NoError counterpart
top-non-begin ; . top-non-begin ; .
@ -26,7 +27,7 @@
resolve ; identifier resolve ; identifier
enter-macro ; syntax enter-macro ; syntax
macro-pre-transform ; syntax macro-pre-transform ; syntax
macro-post-transform ; syntax macro-post-transform ; (cons syntax syntax)
exit-macro ; syntax exit-macro ; syntax
enter-prim ; syntax enter-prim ; syntax
exit-prim ; syntax exit-prim ; syntax
@ -73,6 +74,7 @@
local-value ; identifier local-value ; identifier
local-value-result ; boolean local-value-result ; boolean
local-value-binding ; result of identifier-binding; added by trace.rkt, not expander local-value-binding ; result of identifier-binding; added by trace.rkt, not expander
local-mess ; (listof event)
)) ))
(define-tokens renames-tokens (define-tokens renames-tokens
@ -113,6 +115,7 @@
(#f local-remark ,token-local-remark) (#f local-remark ,token-local-remark)
(#f local-artificial-step ,token-local-artificial-step) (#f local-artificial-step ,token-local-artificial-step)
(#f local-value-binding ,token-local-value-binding) (#f local-value-binding ,token-local-value-binding)
(#f local-mess ,token-local-mess)
;; Standard signals ;; Standard signals
(0 visit ,token-visit) (0 visit ,token-visit)
@ -198,6 +201,7 @@
(157 prepare-env) (157 prepare-env)
(158 prim-submodule) (158 prim-submodule)
(159 prim-submodule*) (159 prim-submodule*)
(160 exit-local-bind)
)) ))
(define (signal->symbol sig) (define (signal->symbol sig)

View File

@ -1,6 +1,7 @@
#lang racket/base #lang racket/base
(require (for-syntax racket/base) (require (for-syntax racket/base)
racket/match racket/match
racket/format
syntax/stx syntax/stx
"../util/eomap.rkt" "../util/eomap.rkt"
"deriv-util.rkt" "deriv-util.rkt"
@ -505,7 +506,17 @@
]] ]]
[(struct local-remark (contents)) [(struct local-remark (contents))
(R [#:reductions (list (walk/talk 'remark contents))])] (R [#:reductions (list (walk/talk 'remark contents))])]
[(struct local-mess (events))
;; FIXME: While it is not generally possible to parse tokens as one or more
;; interrupted derivations (possibly interleaved with successful derivs),
;; it should be possible to recover *some* information and display it.
(R [#:reductions
(let ([texts
(list (~a "Some expansion history has been lost due to a jump "
"within expansion.")
(~a "For example, a macro may have caught an "
"exception coming from within a call to `local-expand'."))])
(list (walk/talk 'remark texts)))])]
[#f [#f
(R)])) (R)]))

View File

@ -1,5 +1,6 @@
#lang racket/base #lang racket/base
(require racket/promise (require racket/promise
racket/list
syntax/modcode syntax/modcode
syntax/modresolve syntax/modresolve
parser-tools/lex parser-tools/lex
@ -76,20 +77,58 @@
;; expand/events : stx (stx -> stx) -> stx/exn (list-of event) ;; expand/events : stx (stx -> stx) -> stx/exn (list-of event)
(define (expand/events sexpr expander) (define (expand/events sexpr expander)
(define events null) (define events null)
;; Problem: jumps within expansion (eg, macro catches error thrown from within
;; call to 'local-expand') can result in ill-formed event stream.
;; In general, not possible to detect jump endpoints, but we can at least isolate
;; the bad parts by watching for mismatched bracketing events
;; (eg, macro-{pre,post}-transform).
(define counter 0) ;; = (length events)
(define macro-stack null) ;; (listof (cons (U stx 'local-bind) nat))
(define (add! x y) (define (add! x y)
(set! counter (add1 counter))
(set! events (cons (cons (signal->symbol x) y) events))) (set! events (cons (cons (signal->symbol x) y) events)))
(define add!/check (define add!/check
(let ([limit (trace-macro-limit)] (let ([limit (trace-macro-limit)]
[handler (trace-limit-handler)] [handler (trace-limit-handler)]
[counter 0] [limit-counter 0]
[last-local-value-id #f]) [last-local-value-id #f])
(lambda (x y) (lambda (x y)
(add! x y) (add! x y)
(case x (case x
((8) ;; enter-macro ((8) ;; enter-macro
(set! counter (add1 counter)) (set! limit-counter (add1 limit-counter))
(when (>= counter limit) (when (>= limit-counter limit)
(set! limit (handler counter)))) (set! limit (handler limit-counter))))
((21) ;; macro-pre-transform
(let ([rec (cons y counter)])
(set! macro-stack (cons rec macro-stack))))
((22) ;; macro-post-transform
(cond [(and (pair? macro-stack)
(eq? (car (car macro-stack)) (cdr y)))
(set! macro-stack (cdr macro-stack))]
[else ;; Jumped!
(let loop ([ms macro-stack])
(let ([top (car ms)])
(cond [(eq? (car top) (cdr y))
(let* ([reset-to (cdr top)]
[len (- counter reset-to 1)]
[pfx (take (cdr events) len)]
[sfx (drop (cdr events) len)])
(set! macro-stack (cdr ms))
(set! events sfx)
(set! counter (cdr top))
(add! 'local-mess (reverse pfx))
(add! 'macro-post-transform y))]
[else (loop (cdr ms))])))]))
((143) ;; local-bind
(let ([rec (cons 'local-bind counter)])
(set! macro-stack (cons rec macro-stack))))
((160) ;; exit-local-bind
(let ([top (car macro-stack)])
(cond [(eq? (car top) 'local-bind)
(set! macro-stack (cdr macro-stack))]
[else ;; Jumped!
(error 'trace "internal error: cannot handle catch within bind")])))
((153) ;; local-value ((153) ;; local-value
(set! last-local-value-id y)) (set! last-local-value-id y))
((154) ;; local-value-result ((154) ;; local-value-result
@ -107,7 +146,6 @@
(values result (values result
(reverse events))))) (reverse events)))))
(require syntax/stx (require syntax/stx
syntax/kerncase) syntax/kerncase)

View File

@ -223,4 +223,17 @@
(define-values (y) 2))))]) (define-values (y) 2))))])
(check-pred deriv? d) (check-pred deriv? d)
(check-pred ok-node? d))) (check-pred ok-node? d)))
;; Added 10/11/2012 based on bug from mflatt,shriram
(test-case "recover from jump"
(let ([d (trace '(module m racket/base
(require (for-syntax racket/base))
(define-syntax (convert-error stx)
(syntax-case stx ()
[(convert-error expr)
(with-handlers ([exn? (lambda (e) #'(quote error))])
(local-expand #'expr 'expression null))]))
(convert-error (lambda))))])
(check-pred deriv? d)
(check-pred ok-node? d)))
)) ))