207 lines
6.7 KiB
Scheme
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))
|