racket/collects/macro-debugger/stxclass/private/sc.ss
Matthew Flatt 24739359e4 Ryan's macro-stepper patches
svn: r9794
2008-05-10 11:02:47 +00:00

207 lines
6.7 KiB
Scheme

#lang scheme/base
(require (for-syntax scheme/base
scheme/match
scheme/private/sc
"rep.ss"
"parse.ss"
"util.ss")
scheme/match
syntax/stx
"kws.ss")
(provide define-syntax-class
define-syntax-splice-class
define-basic-syntax-class
define-basic-syntax-class*
parse-sc
attrs-of
debug-rhs
debug-pattern
syntax-parse
syntax-parser
with-patterns
pattern
union
...*
fail-sc
(struct-out failed)
current-expression
current-macro-name)
(define-syntax (define-syntax-class stx)
(syntax-case stx ()
[(define-syntax-class (name arg ...) rhs)
#'(begin (define-syntax name
(make sc 'name
'(arg ...)
(rhs-attrs (parse-rhs (quote-syntax rhs) #t))
((syntax-local-certifier) #'parser)))
(define parser (rhs->parser name rhs (arg ...))))]
[(define-syntax-class name rhs)
#'(define-syntax-class (name) rhs)]))
(define-syntax (define-syntax-splice-class stx)
(syntax-case stx ()
[(define-syntax-splice-class (name arg ...) rhs)
#'(begin (define-syntax name
(make ssc 'name
'(arg ...)
(rhs-attrs (parse-splice-rhs (quote-syntax rhs) #t))
((syntax-local-certifier) #'parser)))
(define parser (splice-rhs->parser name rhs (arg ...))))]
[(define-syntax-splice-class name rhs)
#'(define-syntax-splice-class (name) rhs)]))
(define-syntax define-basic-syntax-class
(syntax-rules ()
[(define-basic-syntax-class (name arg ...)
([attr-name attr-depth] ...)
parser-expr)
(define-basic-syntax-class* (name arg ...)
([attr-name attr-depth] ...)
(let ([name parser-expr])
(let ([name
(lambda (x arg ...)
(let ([r (name x arg ...)])
(if (ok? r)
(cons x r)
r)))])
name)))]
[(define-basic-syntax-class name
([attr-name attr-depth] ...)
parser-expr)
(define-basic-syntax-class (name)
([attr-name attr-depth] ...)
parser-expr)]))
(define-syntax define-basic-syntax-class*
(syntax-rules ()
[(define-basic-syntax-class* (name arg ...)
([attr-name attr-depth] ...)
parser-expr)
(begin (define parser (let ([name parser-expr]) name))
(define-syntax name
(make sc 'name
'(arg ...)
(list (make-attr 'attr-name 'attr-depth null) ...)
((syntax-local-certifier) #'parser))))]))
(define-syntax (rhs->parser stx)
(syntax-case stx ()
[(rhs->parser name rhs (arg ...))
(let ([rhs (parse-rhs #'rhs #f)]
[sc (syntax-local-value #'name)])
(parse:rhs rhs
(sc-attrs sc)
(syntax->list #'(arg ...))))]))
(define-syntax (parse-sc stx)
(syntax-case stx ()
[(parse s x arg ...)
(let* ([stxclass (get-stxclass #'s)]
[attrs (flatten-sattrs (sc-attrs stxclass))])
(with-syntax ([parser (sc-parser-name stxclass)]
[(name ...) (map attr-name attrs)]
[(depth ...) (map attr-depth attrs)])
#'(let ([raw (parser x arg ...)])
(if (ok? raw)
(map vector '(name ...) '(depth ...) (cdr raw))
raw))))]))
(define-syntax (attrs-of stx)
(syntax-case stx ()
[(attrs-of s)
(let ([attrs (flatten-sattrs (sc-attrs (get-stxclass #'s)))])
(with-syntax ([(a ...) (map attr-name attrs)]
[(depth ...) (map attr-depth attrs)])
#'(quote ((a depth) ...))))]))
(define-syntax (debug-rhs stx)
(syntax-case stx ()
[(debug-rhs rhs)
(let ([rhs (parse-rhs #'rhs #f)])
#`(quote #,rhs))]))
(define-syntax (debug-pattern stx)
(syntax-case stx ()
[(debug-pattern p)
(let ([pattern (parse-pattern #'p)])
#`(quote #,pattern))]))
(define-syntax (syntax-parser stx)
(syntax-case stx ()
[(syntax-parser . clauses)
#`(lambda (x)
(parameterize ((current-expression (or (current-expression) x)))
#,(parse:clauses #'clauses #'x #'syntax-patterns-fail)))]))
(define-syntax (syntax-parse stx)
(syntax-case stx ()
[(syntax-parse expr . clauses)
#`(let ([x expr])
(parameterize ((current-expression (or (current-expression) x)))
#,(parse:clauses #'clauses #'x #'syntax-patterns-fail)))]))
(define-syntax with-patterns
(syntax-rules ()
[(with-patterns () . b)
(let () . b)]
[(with-patterns ([p x] . more) . b)
(syntax-parse x [p (with-patterns more . b)])]))
(define (syntax-patterns-fail x expected reason frontier)
(define (err msg stx)
(raise (make-exn:fail:syntax (string->immutable-string msg)
(current-continuation-marks)
(list stx))))
(define-values (stx n) (frontier->syntax frontier))
(cond [(stx-null? x)
(err (format "missing ~s" expected)
(datum->syntax stx x
(list (syntax-source stx)
#f
#f
(and (syntax-position stx)
(syntax-span stx)
(+ (syntax-position stx)
(syntax-span stx)
-1))
1)))]
[(equal? expected '())
;; FIXME: "extra term(s) after <pattern>"
(syntax-case x ()
[(one)
(err "unexpected term" #'one)]
[(first . more)
(err "unexpected terms starting here" #'first)]
[_
(err "expected end of list" x)])]
[expected
(err (format "expected ~s~a"
expected
(cond [(zero? n) ""]
[(= n +inf.0) " after matching main pattern"]
[else (format " after ~s ~a"
n
(if (= 1 n) "form" "forms"))]))
stx)]
[reason
(format "~a" reason)]
[else
(err "failed" stx)]))
(define (frontier->syntax f)
(match f
[(list x n)
(values x n)]
[(list-rest _ _ rest)
(frontier->syntax rest)]))
(define (fail-sc stx #:pattern [pattern #f] #:reason [reason #f])
(make-failed stx pattern reason))