racket/collects/macro-debugger/model/yacc-interrupted.ss
Ryan Culpepper d91e2b4502 Added the macro stepper
svn: r3987
2006-08-08 20:32:58 +00:00

219 lines
8.3 KiB
Scheme

(module yacc-interrupted mzscheme
(require "deriv.ss"
"yacc-ext.ss")
(provide ! ?
production/I
productions/I
skipped-token-values
%skipped
%action)
;; Grammar macros for "interrupted parses"
;; Uses interrupted-wrap and error-wrap from deriv.ss
(define-syntax !
(lambda (stx)
(raise-syntax-error #f "keyword ! used out of context" stx)))
(define-syntax ?
(lambda (stx)
(raise-syntax-error #f "keyword ? used out of context" stx)))
(define-syntax (productions/I stx)
(syntax-case stx ()
[(productions/I def ...)
#'(begin (production/I def) ...)]))
(define-for-syntax (partition-options/alternates forms)
(let loop ([forms forms] [options null] [alts null])
(if (pair? forms)
(syntax-case (car forms) ()
[(#:args . args)
(loop (cdr forms) (cons (cons #:args #'args) options) alts)]
[(#:skipped expr)
(loop (cdr forms) (cons (cons #:skipped #'expr) options) alts)]
[(#:no-interrupted)
(loop (cdr forms) (cons (cons #:no-interrupted #t) options) alts)]
[(#:no-wrap)
(loop (cdr forms) (cons (cons #:no-wrap #t) options) alts)]
[(#:no-wrap-error)
(loop (cdr forms) (cons (cons #:no-wrap-error #t) options) alts)]
[(kw . args)
(keyword? (syntax-e #'kw))
(raise-syntax-error #f "bad keyword" (car forms))]
[(pattern action)
(loop (cdr forms) options (cons (cons #'pattern #'action) alts))])
(values options (reverse alts)))))
(define-for-syntax (symbol+ . args)
(define (norm x)
(cond [(identifier? x) (norm (syntax-e x))]
[(string? x) x]
[(number? x) (number->string x)]
[(symbol? x) (symbol->string x)]))
(string->symbol (apply string-append (map norm args))))
(define-for-syntax (I symbol)
(syntax-local-introduce
(syntax-local-get-shadower (datum->syntax-object #f symbol))))
(define-for-syntax (elaborate-skipped-tail head tail action)
(define new-tail
(let loop ([parts tail])
(syntax-case parts (? !)
[() #'()]
[(! . parts-rest) (loop #'((! #f) . parts-rest))]
[((! expr) . parts-rest)
(with-syntax ([NoError (I 'NoError)]
[parts-rest (loop #'parts-rest)])
#'(NoError . parts-rest))]
[((? NT) . parts-rest)
(loop #'((? NT #f) . parts-rest))]
[((? NT expr) . parts-rest)
(loop #'(NT . parts-rest))]
[(part0 . parts-rest)
(identifier? #'part0)
(with-syntax ([part0/Skipped (I (symbol+ #'part0 '/Skipped))]
[parts-rest (loop #'parts-rest)])
#'(part0/Skipped . parts-rest))])))
(with-syntax ([head head]
[new-tail new-tail])
(cons #'(head . new-tail)
action)))
(define-for-syntax (elaborate-successful-alternate alt)
(define pattern (car alt))
(define action (cdr alt))
(cons (let loop ([parts pattern])
(syntax-case parts (? !)
[() #'()]
[(! . parts-rest)
(loop #'((! #f) . parts-rest))]
[((! expr) . parts-rest)
(with-syntax ([NoError (I 'NoError)]
[parts-rest (loop #'parts-rest)])
#'(NoError . parts-rest))]
[((? NT) . parts-rest)
(loop #'((? NT #f) . parts-rest))]
[((? NT expr) . parts-rest)
(with-syntax ([parts-rest (loop #'parts-rest)])
#'(NT . parts-rest))]
[(part0 . parts-rest)
(identifier? #'part0)
(with-syntax ([parts-rest (loop #'parts-rest)])
#'(part0 . parts-rest))]))
action))
(define-for-syntax (elaborate-interrupted-alternate alt wrap? wrap-error?)
(define pattern (car alt))
(define action (cdr alt))
(let loop ([parts pattern] [position 1])
(syntax-case parts (? !)
[()
;; Can't be interrupted
null]
[(! . parts-rest)
(loop #'((! #f) . parts-rest) position)]
[((! expr) . parts-rest)
(cons
;; Error occurs
(with-syntax ([Error (I 'syntax-error #;Error)]
[action action]
[position-argument (I (symbol+ '$ position))])
(elaborate-skipped-tail
#'Error
#'parts-rest
(if wrap-error?
#'(make-error-wrap position-argument expr action)
#'action)))
;; Error doesn't occur
(with-syntax ([NoError (I 'NoError)])
(loop #'(NoError . parts-rest) position)))]
[((? NT) . parts-rest)
(loop #'((? NT #f) . parts-rest) position)]
[((? NT expr) . parts-rest)
(cons
;; NT is interrupted
(with-syntax ([NT/I (I (symbol+ #'NT '/Interrupted))]
[action action])
(elaborate-skipped-tail
#'NT/I
#'parts-rest
(if wrap?
#'(make-interrupted-wrap expr action)
#'action)))
;; NT is not interrupted
(loop #'(NT . parts-rest) position))]
[(part0 . parts-rest)
(identifier? #'part0)
(map (lambda (clause) (cons #`(part0 . #,(car clause)) (cdr clause)))
(loop #'parts-rest (add1 position)))])))
(define-syntax (production/I stx)
(syntax-case stx ()
[(production/I (name form ...))
(let ()
(define-values (options alternates)
(partition-options/alternates (syntax->list #'(form ...))))
(define successful-alternates
(map elaborate-successful-alternate alternates))
(define interrupted-alternates
(apply append
(map (lambda (a)
(elaborate-interrupted-alternate a
(not (assq #:no-wrap options))
(not (assq #:no-wrap-error options))))
alternates)))
(with-syntax ([((success-pattern . success-action) ...)
successful-alternates]
[((interrupted-pattern . interrupted-action) ...)
interrupted-alternates]
[skip-spec (assq #:skipped options)]
[args-spec (assq #:args options)]
[name/Skipped (I (symbol+ #'name '/Skipped))]
[name/Interrupted (I (symbol+ #'name '/Interrupted))]
[%action ((syntax-local-certifier) #'%action)])
#`(begin
(productions
(name [success-pattern
(%action args-spec success-action)]
...)
(name/Skipped [() (%skipped args-spec skip-spec)]))
#,(if (and (not (assq #:no-interrupted options))
(pair? interrupted-alternates))
#'(productions
(name/Interrupted [interrupted-pattern
(%action args-spec interrupted-action)]
...))
#'(begin)))))]))
(define-syntax (skipped-token-values stx)
(syntax-case stx ()
[(skipped-token-values)
#'(begin)]
[(skipped-token-values name . more)
(identifier? #'name)
(with-syntax ([name/Skipped (I (symbol+ #'name '/Skipped))])
#'(begin (productions (name/Skipped [() #f]))
(skipped-token-values . more)))]
[(skipped-token-values (name value) . more)
(with-syntax ([name/Skipped (I (symbol+ #'name '/Skipped))])
#'(begin (productions (name/Skipped [() value]))
(skipped-token-values . more)))]))
(define-syntax (%skipped stx)
(syntax-case stx ()
[(%skipped args (#:skipped . expr))
#'(%action args expr)]
[(%skipped args #f)
#'(%action args #f)]))
(define-syntax (%action stx)
(syntax-case stx ()
[(elaborate-action (#:args . args) action)
#'(lambda args action)]
[(elaborate-action #f action)
#'action]))
)