stxclass: minor improvements to syntax, docs, literals, etc

svn: r11808
This commit is contained in:
Ryan Culpepper 2008-09-18 19:37:09 +00:00
parent d44850f515
commit f22c42d8a4
8 changed files with 323 additions and 213 deletions

View File

@ -1,5 +1,5 @@
#lang setup/infotab #lang setup/infotab
;; Not ready yet ;; Not ready yet
#;(define scribblings '(("stxclass.scrbl"))) (define scribblings '(("stxclass.scrbl")))
(define compile-omit-paths '("test.ss")) (define compile-omit-paths '("test.ss"))

View File

@ -2,7 +2,6 @@
(require scheme/stxparam (require scheme/stxparam
(for-syntax scheme/base)) (for-syntax scheme/base))
(provide pattern (provide pattern
union
...* ...*
try try
@ -15,13 +14,15 @@
current-expression current-expression
current-macro-name) current-macro-name)
;; (define-syntax-class name SyntaxClassRHS) ;; (define-syntax-class name SyntaxClassDirective* SyntaxClassRHS*)
;; (define-syntax-class (name id ...) SyntaxClassRHS) ;; (define-syntax-class (name id ...) SyntaxClassDirective* SyntaxClassRHS*)
;; A SyntaxClassRHS is one of ;; A SCDirective is one of
;; #:description String
;; #:transparent
;; A SyntaxClassRHS is
;; (pattern Pattern PatternDirective ...) ;; (pattern Pattern PatternDirective ...)
;; (union SyntaxClassRHS ...)
;; syntax-class-id
;; A Pattern is one of ;; A Pattern is one of
;; name:syntaxclass ;; name:syntaxclass
@ -56,7 +57,6 @@
(raise-syntax-error #f "keyword used out of context" stx)))) (raise-syntax-error #f "keyword used out of context" stx))))
(define-keyword pattern) (define-keyword pattern)
(define-keyword union)
(define-keyword ...*) (define-keyword ...*)
(define-keyword ...**) (define-keyword ...**)
@ -75,10 +75,15 @@
(define (current-macro-name) (define (current-macro-name)
(let ([expr (current-expression)]) (let ([expr (current-expression)])
(and expr (and expr
(syntax-case expr () (syntax-case expr (set!)
[(set! kw . _)
#'kw]
[(kw . _) [(kw . _)
(identifier? #'kw) (identifier? #'kw)
#'kw] #'kw]
[kw
(identifier? #'kw)
#'kw]
[_ #f])))) [_ #f]))))
;; A PatternParseResult is one of ;; A PatternParseResult is one of
@ -113,7 +118,8 @@
(let loop ([f1 frontier1] [f2 frontier2]) (let loop ([f1 frontier1] [f2 frontier2])
(cond [(and (null? f1) (null? f2)) (cond [(and (null? f1) (null? f2))
;; FIXME: merge ;; FIXME: merge
(k x1 `(union ,p1 ,p2) #f frontier1)] (let ([p (and p1 p2 (format "~a; or ~a" p1 p2))])
(k x1 p #f frontier1))]
[(and (pair? f1) (null? f2)) (go1)] [(and (pair? f1) (null? f2)) (go1)]
[(and (null? f1) (pair? f2)) (go2)] [(and (null? f1) (pair? f2)) (go2)]
[(and (pair? f1) (pair? f2)) [(and (pair? f1) (pair? f2))

View File

@ -1,6 +1,7 @@
#lang scheme/base #lang scheme/base
(require "sc.ss" (require "sc.ss"
"util.ss"
syntax/stx syntax/stx
syntax/kerncase syntax/kerncase
scheme/struct-info scheme/struct-info
@ -49,8 +50,8 @@
(define-syntax-class define-syntaxes-form (define-syntax-class define-syntaxes-form
(pattern (kw:define-syntaxes-kw (var:identifier ...) rhs))) (pattern (kw:define-syntaxes-kw (var:identifier ...) rhs)))
(define-syntax-class definition-form (define-syntax-class definition-form
(union define-values-form (pattern :define-values-form)
define-syntaxes-form)) (pattern :define-syntaxes-form))
(define-basic-syntax-class static (define-basic-syntax-class static
([datum 0] [value 0]) ([datum 0] [value 0])
@ -123,7 +124,7 @@
[expr 1]) [expr 1])
(lambda (x) (lambda (x)
(let-values ([(ex1 ex2 defs vdefs sdefs exprs) (let-values ([(ex1 ex2 defs vdefs sdefs exprs)
(head-local-expand-syntaxes x #f #t)]) (head-local-expand-and-categorize-syntaxes x #f #; #t)])
(list ex1 ex2 defs vdefs sdefs exprs)))) (list ex1 ex2 defs vdefs sdefs exprs))))
(define-basic-syntax-class internal-definitions (define-basic-syntax-class internal-definitions
@ -135,72 +136,9 @@
[expr 1]) [expr 1])
(lambda (x) (lambda (x)
(let-values ([(ex1 ex2 defs vdefs sdefs exprs) (let-values ([(ex1 ex2 defs vdefs sdefs exprs)
(head-local-expand-syntaxes x #t #f)]) (head-local-expand-and-categorize-syntaxes x #t #; #f)])
(list ex1 ex2 defs vdefs sdefs exprs)))) (list ex1 ex2 defs vdefs sdefs exprs))))
;; head-local-expand-syntaxes : syntax boolean boolean -> stxs ^ 6
;; Setting allow-def-after-expr? allows def/expr interleaving.
;; Setting need-expr? requires at least one expr to be present.
(define (head-local-expand-syntaxes x allow-def-after-expr? need-expr?)
(let ([intdef (syntax-local-make-definition-context)]
[ctx '(block)])
(let loop ([x x] [ex null] [defs null] [vdefs null] [sdefs null] [exprs null])
(cond [(stx-pair? x)
(let ([ee (local-expand (stx-car x)
ctx
(kernel-form-identifier-list)
intdef)])
(syntax-case ee (begin define-values define-syntaxes)
[(begin e ...)
(loop (append (syntax->list #'(e ...)) (stx-cdr x)) ex defs vdefs sdefs exprs)]
[(begin . _)
(raise-syntax-error #f "bad begin form" ee)]
[(define-values (var ...) rhs)
(andmap identifier? (syntax->list #'(var ...)))
(begin
(when (and (pair? exprs) (not allow-def-after-expr?))
(raise-syntax-error #f "definition after expression" ee))
(syntax-local-bind-syntaxes (syntax->list #'(var ...)) #f intdef)
(loop (stx-cdr x)
(cons ee ex)
(cons ee defs)
(cons ee vdefs)
sdefs
exprs))]
[(define-values . _)
(raise-syntax-error #f "bad define-values form" ee)]
[(define-syntaxes (var ...) rhs)
(andmap identifier? (syntax->list #'(var ...)))
(begin
(when (and (pair? exprs) (not allow-def-after-expr?))
(raise-syntax-error #f "definition after expression" ee))
(syntax-local-bind-syntaxes (syntax->list #'(var ...))
#'rhs
intdef)
(loop (stx-cdr x)
(cons ee ex)
(cons ee defs)
vdefs
(cons ee sdefs)
exprs))]
[(define-syntaxes . _)
(raise-syntax-error #f "bad define-syntaxes form" ee)]
[_
(loop (stx-cdr x)
(cons ee ex)
defs
vdefs
sdefs
(cons ee exprs))]))]
[(stx-null? x)
(let ([ex (reverse ex)])
(values ex
ex
(reverse defs)
(reverse vdefs)
(reverse sdefs)
(reverse exprs)))]))))
(define-syntax-rule (define-contract-stxclass name c) (define-syntax-rule (define-contract-stxclass name c)
(define-basic-syntax-class* (name) (define-basic-syntax-class* (name)
([orig-stx 0]) ([orig-stx 0])

View File

@ -72,8 +72,12 @@
;; rhs->pks : RHS (listof SAttr) identifier -> (listof PK) ;; rhs->pks : RHS (listof SAttr) identifier -> (listof PK)
(define (rhs->pks rhs relsattrs main-var) (define (rhs->pks rhs relsattrs main-var)
(match rhs (match rhs
[(struct rhs:union (orig-stx attrs rhss)) [(struct rhs:union (orig-stx attrs transparent? description patterns))
(for*/list ([rhs rhss] [pk (rhs->pks rhs relsattrs main-var)]) pk)] (for*/list ([rhs patterns] [pk (rhs-pattern->pks rhs relsattrs main-var)])
pk)]))
(define (rhs-pattern->pks rhs relsattrs main-var)
(match rhs
[(struct rhs:pattern (orig-stx attrs pattern decls remap sides)) [(struct rhs:pattern (orig-stx attrs pattern decls remap sides))
(list (make-pk (list pattern) (list (make-pk (list pattern)
(expr:convert-sides sides (expr:convert-sides sides
@ -143,7 +147,7 @@
#:literals literals)]) #:literals literals)])
(syntax-case rest () (syntax-case rest ()
[(b) [(b)
(let* ([pattern (parse-pattern #'p decls)]) (let* ([pattern (parse-pattern #'p decls 0)])
(make-pk (list pattern) (make-pk (list pattern)
(expr:convert-sides sides (expr:convert-sides sides
(pattern-attrs pattern) (pattern-attrs pattern)
@ -202,6 +206,55 @@
#`(let-syntax ([failvar (make-rename-transformer (quote-syntax #,failid))]) #`(let-syntax ([failvar (make-rename-transformer (quote-syntax #,failid))])
(try failvar (expr ...))))))])) (try failvar (expr ...))))))]))
(define (report-stxclass stxclass)
(and stxclass
(format "expected ~a"
(or (sc-description stxclass)
(sc-name stxclass)))))
(define (report-constants pairs? data literals)
(cond [pairs? #f]
[(null? data)
(format "expected ~a" (report-choices-literals literals))]
[(null? literals)
(format "expected ~a" (report-choices-data data))]
[else
(format "expected ~a; or ~a"
(report-choices-data data)
(report-choices-literals literals))]))
(define (report-choices-literals literals0)
(define literals
(sort (map syntax-e literals0)
string<?
#:key symbol->string
#:cache-keys? #t))
(case (length literals)
[(1) (format "the literal identifier ~s" (car literals))]
[else (format "one of the following literal identifiers: ~a"
(comma-list literals))]))
(define (report-choices-data data)
(case (length data)
[(1) (format "the datum ~s" (car data))]
[else (format "one of the following literals: ~a"
(comma-list data))]))
(define (comma-list items0)
(define items (for/list ([item items0]) (format "~s" item)))
(define (loop items)
(cond [(null? items)
null]
[(null? (cdr items))
(list ", or " (car items))]
[else
(list* ", " (car items) (loop (cdr items)))]))
(case (length items)
[(2) (format "~a or ~a" (car items) (cadr items))]
[else (let ([strings (list* (car items) (loop (cdr items)))])
(apply string-append strings))]))
;; parse:extpk : (listof identifier) (listof FC) ExtPK identifier -> stx ;; parse:extpk : (listof identifier) (listof FC) ExtPK identifier -> stx
;; Pre: vars is not empty ;; Pre: vars is not empty
(define (parse:extpk vars fcs extpk failid) (define (parse:extpk vars fcs extpk failid)
@ -217,7 +270,7 @@
(if (ok? r) (if (ok? r)
#,(parse:pks (cdr vars) (cdr fcs) (shift-pks:id pks #'r) failid) #,(parse:pks (cdr vars) (cdr fcs) (shift-pks:id pks #'r) failid)
#,(fail failid (car vars) #,(fail failid (car vars)
#:pattern (and stxclass (sc-name stxclass)) #:pattern (report-stxclass stxclass)
#:fc (car fcs)))))] #:fc (car fcs)))))]
[(struct cpks (pairpks datumpkss literalpkss)) [(struct cpks (pairpks datumpkss literalpkss))
(with-syntax ([var0 (car vars)] (with-syntax ([var0 (car vars)]
@ -270,13 +323,13 @@
#'()) #'())
[datum-test datum-rhs] ... [datum-test datum-rhs] ...
[else [else
#,(let ([ps #'(pair-pattern ... datum-pattern ...)]) #,(fail failid (car vars)
(with-syntax ([ep (if (= (length (syntax->list ps)) 1) #:pattern (report-constants (pair? pairpks)
(car (syntax->list ps)) (for/list ([d datumpkss])
#`(union #,@ps))]) (datumpks-datum d))
(fail failid (car vars) (for/list ([l literalpkss])
#:pattern #'ep (literalpks-literal l)))
#:fc (car fcs))))]))))] #:fc (car fcs))]))))]
#; #;
[(struct pk ((cons (struct pat:splice (orig-stx attrs depth head tail)) [(struct pk ((cons (struct pat:splice (orig-stx attrs depth head tail))
rest-ps) rest-ps)

View File

@ -31,7 +31,7 @@
format-symbol) format-symbol)
;; An SC is one of (make-sc symbol (listof symbol) (list-of SAttr) identifier) ;; An SC is one of (make-sc symbol (listof symbol) (list-of SAttr) identifier)
(define-struct sc (name inputs attrs parser-name) (define-struct sc (name inputs attrs parser-name description)
#:property prop:procedure (lambda (self stx) (sc-parser-name self)) #:property prop:procedure (lambda (self stx) (sc-parser-name self))
#:transparent) #:transparent)
@ -44,13 +44,19 @@
(define-struct attr (name depth inner) (define-struct attr (name depth inner)
#:transparent) #:transparent)
;; A RHS is one of ;; RHSBase is stx (listof SAttr)
;; (make-rhs:union <RHS> (listof RHS)) (define-struct rhs (orig-stx attrs)
;; (make-rhs:pattern <RHS> Pattern Env Env (listof SideClause)) #:transparent)
;; where <RHS> is stx (listof SAttr)
(define-struct rhs (orig-stx attrs) #:transparent) ;; A RHS is
(define-struct (rhs:union rhs) (rhss) #:transparent) ;; (make-rhs:union <RHSBase> (listof RHS))
(define-struct (rhs:pattern rhs) (pattern decls remap wheres) #:transparent) (define-struct (rhs:union rhs) (transparent? description patterns)
#:transparent)
;; An RHSPattern is
;; (make-rhs:pattern <RHSBase> Pattern Env Env (listof SideClause))
(define-struct (rhs:pattern rhs) (pattern decls remap wheres)
#:transparent)
;; A Pattern is one of ;; A Pattern is one of
;; (make-pat:id <Pattern> identifier SC/#f (listof stx)) ;; (make-pat:id <Pattern> identifier SC/#f (listof stx))
@ -88,7 +94,7 @@
;; make-empty-sc : identifier => SC ;; make-empty-sc : identifier => SC
;; Dummy stxclass for calculating attributes of recursive stxclasses. ;; Dummy stxclass for calculating attributes of recursive stxclasses.
(define (make-empty-sc name) (define (make-empty-sc name)
(make sc (syntax-e name) null null #f)) (make sc (syntax-e name) null null #f #f))
(define (iattr? a) (define (iattr? a)
(and (attr? a) (identifier? (attr-name a)))) (and (attr? a) (identifier? (attr-name a))))
@ -101,8 +107,8 @@
[sattr? (any/c . -> . boolean?)] [sattr? (any/c . -> . boolean?)]
[reorder-iattrs [reorder-iattrs
((listof sattr?) (listof iattr?) (identifier? . -> . symbol?) . -> . (listof iattr?))] ((listof sattr?) (listof iattr?) (identifier? . -> . symbol?) . -> . (listof iattr?))]
[parse-rhs (syntax? boolean? . -> . rhs?)] [parse-rhs (syntax? boolean? syntax? . -> . rhs?)]
[parse-splice-rhs (syntax? boolean? . -> . rhs?)] [parse-splice-rhs (syntax? boolean? syntax? . -> . rhs?)]
[flatten-sattrs [flatten-sattrs
([(listof sattr?)] [exact-integer? (or/c symbol? false/c)] . ->* . (listof sattr?))] ([(listof sattr?)] [exact-integer? (or/c symbol? false/c)] . ->* . (listof sattr?))]
@ -208,25 +214,51 @@
(define allow-unbound-stxclasses (make-parameter #f)) (define allow-unbound-stxclasses (make-parameter #f))
;; parse-rhs : stx(SyntaxClassRHS) boolean -> RHS ;; parse-rhs : stx(SyntaxClassRHS) boolean stx -> RHS
;; If allow-unbound? is true, then unbound stxclass acts as if it has no attrs. ;; If allow-unbound? is true, then unbound stxclass acts as if it has no attrs.
;; Used for pass1 (attr collection); parser requires stxclasses to be bound. ;; Used for pass1 (attr collection); parser requires stxclasses to be bound.
(define (parse-rhs stx allow-unbound?) (define (parse-rhs stx allow-unbound? ctx)
(parse-rhs* stx allow-unbound? #f)) (parse-rhs* stx allow-unbound? #f ctx))
;; parse-splice-rhs : stx(SyntaxClassRHS) boolean -> RHS ;; parse-splice-rhs : stx(SyntaxClassRHS) boolean stx -> RHS
;; If allow-unbound? is true, then unbound stxclass acts as if it has no attrs. ;; If allow-unbound? is true, then unbound stxclass acts as if it has no attrs.
;; Used for pass1 (attr collection); parser requires stxclasses to be bound. ;; Used for pass1 (attr collection); parser requires stxclasses to be bound.
(define (parse-splice-rhs stx allow-unbound?) (define (parse-splice-rhs stx allow-unbound? ctx)
(parse-rhs* stx allow-unbound? #t)) (parse-rhs* stx allow-unbound? #t ctx))
;; parse-rhs* : stx boolean boolean -> RHS ;; parse-rhs* : stx boolean boolean -> RHS
(define (parse-rhs* stx allow-unbound? splice?) (define (parse-rhs* stx allow-unbound? splice? ctx)
(syntax-case stx (pattern union) (define-values (chunks rest)
(chunk-kw-seq stx rhs-directive-table #:context ctx))
(define lits (assq '#:literals chunks))
(define desc (assq '#:description chunks))
(define trans (assq '#:transparent chunks))
(define literals (if lits (caddr lits) null))
(define (gather-patterns stx)
(syntax-case stx (pattern)
[((pattern . _) . rest)
(cons (parse-rhs-pattern (stx-car stx) allow-unbound? splice? literals)
(gather-patterns #'rest))]
[()
null]))
(define patterns (gather-patterns rest))
(when (null? patterns)
(raise-syntax-error #f "syntax class has no variants" ctx))
(let ([sattrs (intersect-attrss (map rhs-attrs patterns) ctx)])
(make rhs:union stx sattrs
(and desc (caddr desc))
(and trans #t)
patterns)))
;; parse-rhs-pattern : stx boolean boolean (listof identifier) -> RHS
(define (parse-rhs-pattern stx allow-unbound? splice? literals)
(syntax-case stx (pattern)
[(pattern p . rest) [(pattern p . rest)
(parameterize ((allow-unbound-stxclasses allow-unbound?)) (parameterize ((allow-unbound-stxclasses allow-unbound?))
(let-values ([(rest decls remap clauses) (let-values ([(rest decls remap clauses)
(parse-pattern-directives #'rest #:sc? #t)]) (parse-pattern-directives #'rest
#:literals literals
#:sc? #t)])
(unless (stx-null? rest) (unless (stx-null? rest)
(raise-syntax-error #f "unexpected terms after pattern directives" (raise-syntax-error #f "unexpected terms after pattern directives"
(if (pair? rest) (car rest) rest))) (if (pair? rest) (car rest) rest)))
@ -241,25 +273,16 @@
(map pattern-attrs with-patterns)) (map pattern-attrs with-patterns))
stx)] stx)]
[sattrs (iattrs->sattrs attrs remap)]) [sattrs (iattrs->sattrs attrs remap)])
(make rhs:pattern stx sattrs pattern decls remap clauses))))] (make rhs:pattern stx sattrs pattern decls remap clauses))))]))
[(union p ...)
(let* ([rhss (for/list ([rhs (syntax->list #'(p ...))]) ;; rhs-directive-table
(parse-rhs* rhs allow-unbound? splice?))] (define rhs-directive-table
[sattrs (intersect-attrss (map rhs-attrs rhss) stx)]) (list (list '#:literals check-idlist)
(make rhs:union stx sattrs rhss))] (list '#:description check-string)
[(id arg ...) (list '#:transparent)))
(identifier? #'id)
(parse-rhs* (syntax/loc stx (pattern || #:declare || (id arg ...)))
allow-unbound?
splice?)]
[id
(identifier? #'id)
(parse-rhs* (syntax/loc stx (pattern || #:declare || id))
allow-unbound?
splice?)]))
;; parse-pattern : stx(Pattern) env number -> Pattern ;; parse-pattern : stx(Pattern) env number -> Pattern
(define (parse-pattern stx [decls (lambda _ #f)] [depth 0] [allow-splice? #f]) (define (parse-pattern stx decls depth [allow-splice? #f])
(syntax-case stx () (syntax-case stx ()
[dots [dots
(or (dots? #'dots) (or (dots? #'dots)
@ -354,12 +377,6 @@
(raise-syntax-error 'pattern "expected sequence of patterns or sequence directive" (raise-syntax-error 'pattern "expected sequence of patterns or sequence directive"
(if (pair? stx) (car stx) stx))])) (if (pair? stx) (car stx) stx))]))
(define (check-nat/f stx)
(let ([d (syntax-e stx)])
(unless (nat/f d)
(raise-syntax-error #f "expected exact nonnegative integer or #f" stx))
stx))
(define head-directive-table (define head-directive-table
(list (list '#:min check-nat/f) (list (list '#:min check-nat/f)
(list '#:max check-nat/f) (list '#:max check-nat/f)
@ -369,7 +386,7 @@
(list '#:mand))) (list '#:mand)))
(define (parse-heads-k stx heads heads-attrs heads-depth k) (define (parse-heads-k stx heads heads-attrs heads-depth k)
(define-values (chunks rest) (chunk-kw-seq stx head-directive-table)) (define-values (chunks rest) (chunk-kw-seq/no-dups stx head-directive-table))
(reject-duplicate-chunks chunks) (reject-duplicate-chunks chunks)
(let* ([min-row (assq '#:min chunks)] (let* ([min-row (assq '#:min chunks)]
[max-row (assq '#:max chunks)] [max-row (assq '#:max chunks)]
@ -412,10 +429,6 @@
(and occurs-row (caddr occurs-row)) (and occurs-row (caddr occurs-row))
(and default-row (caddr default-row))))) (and default-row (caddr default-row)))))
;; nat/f : any -> boolean
(define (nat/f x)
(or (not x) (exact-nonnegative-integer? x)))
;; append-attrs : (listof (listof IAttr)) stx -> (listof IAttr) ;; append-attrs : (listof (listof IAttr)) stx -> (listof IAttr)
(define (append-attrs attrss stx) (define (append-attrs attrss stx)
(let* ([all (apply append attrss)] (let* ([all (apply append attrss)]

View File

@ -10,7 +10,6 @@
syntax/stx syntax/stx
"kws.ss") "kws.ss")
(provide define-syntax-class (provide define-syntax-class
define-syntax-splice-class
define-basic-syntax-class define-basic-syntax-class
define-basic-syntax-class* define-basic-syntax-class*
parse-sc parse-sc
@ -24,7 +23,6 @@
with-patterns with-patterns
pattern pattern
union
...* ...*
fail-sc fail-sc
@ -35,27 +33,32 @@
(define-syntax (define-syntax-class stx) (define-syntax (define-syntax-class stx)
(syntax-case stx () (syntax-case stx ()
[(define-syntax-class (name arg ...) rhs) [(define-syntax-class (name arg ...) . rhss)
#'(begin (define-syntax name #`(begin (define-syntax name
(let ([the-rhs (parse-rhs (quote-syntax rhss) #t (quote-syntax #,stx))])
(make sc 'name (make sc 'name
'(arg ...) '(arg ...)
(rhs-attrs (parse-rhs (quote-syntax rhs) #t)) (rhs-attrs the-rhs)
((syntax-local-certifier) #'parser))) ((syntax-local-certifier) #'parser)
(define parser (rhs->parser name rhs (arg ...))))] (rhs:union-description the-rhs))))
[(define-syntax-class name rhs) (define parser (rhs->parser name rhss (arg ...) #,stx)))]
#'(define-syntax-class (name) rhs)])) [(define-syntax-class name . rhss)
(syntax/loc stx
(define-syntax-class (name) . rhss))]))
#;
(define-syntax (define-syntax-splice-class stx) (define-syntax (define-syntax-splice-class stx)
(syntax-case stx () (syntax-case stx ()
[(define-syntax-splice-class (name arg ...) rhs) [(define-syntax-splice-class (name arg ...) . rhss)
#'(begin (define-syntax name #`(begin (define-syntax name
(make ssc 'name (make ssc 'name
'(arg ...) '(arg ...)
(rhs-attrs (parse-splice-rhs (quote-syntax rhs) #t)) (rhs-attrs
(parse-splice-rhs (quote-syntax rhss) #t (quote-syntax #,stx)))
((syntax-local-certifier) #'parser))) ((syntax-local-certifier) #'parser)))
(define parser (splice-rhs->parser name rhs (arg ...))))] (define parser (splice-rhs->parser name rhss (arg ...) #,stx)))]
[(define-syntax-splice-class name rhs) [(define-syntax-splice-class name . rhss)
#'(define-syntax-splice-class (name) rhs)])) (syntax/loc stx (define-syntax-splice-class (name) . rhss))]))
(define-syntax define-basic-syntax-class (define-syntax define-basic-syntax-class
(syntax-rules () (syntax-rules ()
@ -89,12 +92,13 @@
(make sc 'name (make sc 'name
'(arg ...) '(arg ...)
(list (make-attr 'attr-name 'attr-depth null) ...) (list (make-attr 'attr-name 'attr-depth null) ...)
((syntax-local-certifier) #'parser))))])) ((syntax-local-certifier) #'parser)
#f)))]))
(define-syntax (rhs->parser stx) (define-syntax (rhs->parser stx)
(syntax-case stx () (syntax-case stx ()
[(rhs->parser name rhs (arg ...)) [(rhs->parser name rhss (arg ...) ctx)
(let ([rhs (parse-rhs #'rhs #f)] (let ([rhs (parse-rhs #'rhss #f #'ctx)]
[sc (syntax-local-value #'name)]) [sc (syntax-local-value #'name)])
(parse:rhs rhs (parse:rhs rhs
(sc-attrs sc) (sc-attrs sc)
@ -182,7 +186,7 @@
[_ [_
(err "expected end of list" x)])] (err "expected end of list" x)])]
[expected [expected
(err (format "expected ~s~a" (err (format "~a~a"
expected expected
(cond [(zero? n) ""] (cond [(zero? n) ""]
[(= n +inf.0) " after matching main pattern"] [(= n +inf.0) " after matching main pattern"]
@ -204,3 +208,6 @@
(define (fail-sc stx #:pattern [pattern #f] #:reason [reason #f]) (define (fail-sc stx #:pattern [pattern #f] #:reason [reason #f])
(make-failed stx pattern reason)) (make-failed stx pattern reason))
(define (syntax-class-fail stx #:reason [reason #f])
(make-failed stx #f reason))

View File

@ -3,37 +3,22 @@
(require (for-syntax scheme/base (require (for-syntax scheme/base
scheme/struct-info) scheme/struct-info)
syntax/boundmap syntax/boundmap
syntax/kerncase
syntax/stx) syntax/stx)
(provide make (provide make
chunk-kw-seq/no-dups chunk-kw-seq/no-dups
chunk-kw-seq chunk-kw-seq
reject-duplicate-chunks reject-duplicate-chunks
check-id check-id
#| check-nat/f
monomap? check-string
monomap-get check-idlist
monomap-put!
monomap-map
monomap-for-each
monomap-domain
monomap-range
isomap? head-local-expand-and-categorize-syntaxes
isomap-get categorize-expanded-syntaxes
isomap-reverse-get head-local-expand-syntaxes)
isomap-put!
isomap-map
isomap-for-each
isomap-domain
isomap-range
make-bound-id-monomap
make-free-id-monomap
make-hash-monomap
(rename-out [-make-isomap make-isomap])
|#
)
(define-syntax (make stx) (define-syntax (make stx)
(syntax-case stx () (syntax-case stx ()
@ -80,7 +65,8 @@
[arity (cdr (assq kw-value kws))] [arity (cdr (assq kw-value kws))]
[args+rest (stx-split #'more arity)]) [args+rest (stx-split #'more arity)])
(if args+rest (if args+rest
(loop (cdr args+rest) (cons (list* kw-value #'kw (car args+rest)) rchunks)) (loop (cdr args+rest)
(cons (list* kw-value #'kw (car args+rest)) rchunks))
(raise-syntax-error #f "too few arguments for keyword" #'kw ctx)))] (raise-syntax-error #f "too few arguments for keyword" #'kw ctx)))]
[(kw . more) [(kw . more)
(keyword? (syntax-e #'kw)) (keyword? (syntax-e #'kw))
@ -90,13 +76,14 @@
(loop stx null)) (loop stx null))
(define (reject-duplicate-chunks chunks #:context [ctx #f]) (define (reject-duplicate-chunks chunks #:context [ctx #f])
(define kws (make-hasheq))
(define (loop chunks) (define (loop chunks)
(when (pair? chunks) (when (pair? chunks)
(let* ([kw (caar chunks)] (let ([kw (caar chunks)])
[dup (assq kw (cdr chunks))]) (when (hash-ref kws kw #f)
(when dup (raise-syntax-error #f "duplicate keyword argument" (cadar chunks) ctx))
(raise-syntax-error #f "duplicate keyword argument" (cadr dup) ctx)) (hash-set! kws kw #t))
(loop (cdr chunks))))) (loop (cdr chunks))))
(loop chunks)) (loop chunks))
;; stx-split : stx nat -> (cons (listof stx) stx) ;; stx-split : stx nat -> (cons (listof stx) stx)
@ -115,6 +102,104 @@
(raise-syntax-error 'pattern "expected identifier" stx)) (raise-syntax-error 'pattern "expected identifier" stx))
stx) stx)
(define (check-string stx)
(unless (string? (syntax-e stx))
(raise-syntax-error #f "expected string" stx))
stx)
;; nat/f : any -> boolean
(define (nat/f x)
(or (not x) (exact-nonnegative-integer? x)))
(define (check-nat/f stx)
(let ([d (syntax-e stx)])
(unless (nat/f d)
(raise-syntax-error #f "expected exact nonnegative integer or #f" stx))
stx))
(define (check-idlist stx)
(unless (and (stx-list? stx) (andmap identifier? (stx->list stx)))
(raise-syntax-error #f "expected list of identifiers" stx))
(stx->list stx))
;; head-local-expand-syntaxes : syntax boolean boolean -> stxs ^ 6
;; Setting allow-def-after-expr? allows def/expr interleaving.
(define (head-local-expand-and-categorize-syntaxes x allow-def-after-expr?)
(define estxs (head-local-expand-syntaxes x allow-def-after-expr?))
(define-values (defs vdefs sdefs exprs)
(categorize-expanded-syntaxes estxs))
(values estxs estxs defs vdefs sdefs exprs))
(define (categorize-expanded-syntaxes estxs0)
(let loop ([estxs estxs0] [defs null] [vdefs null] [sdefs null] [exprs null])
(cond [(pair? estxs)
(let ([ee (car estxs)])
(syntax-case ee (begin define-values define-syntaxes)
[(define-values . _)
(loop (cdr estxs)
(cons ee defs)
(cons ee vdefs)
sdefs
exprs)]
[(define-syntaxes (var ...) rhs)
(loop (cdr estxs)
(cons ee defs)
vdefs
(cons ee sdefs)
exprs)]
[_
(loop (cdr estxs)
defs
vdefs
sdefs
(cons ee exprs))]))]
[(null? estxs)
(values (reverse defs)
(reverse vdefs)
(reverse sdefs)
(reverse exprs))])))
;; head-local-expand-syntaxes : syntax boolean -> (listof syntax)
(define (head-local-expand-syntaxes x allow-def-after-expr?)
(let ([intdef (syntax-local-make-definition-context)]
[ctx '(block)])
(let loop ([x x] [ex null] [expr? #f])
(cond [(stx-pair? x)
(let ([ee (local-expand (stx-car x)
ctx
(kernel-form-identifier-list)
intdef)])
(syntax-case ee (begin define-values define-syntaxes)
[(begin e ...)
(loop (append (syntax->list #'(e ...)) (stx-cdr x)) ex expr?)]
[(begin . _)
(raise-syntax-error #f "bad begin form" ee)]
[(define-values (var ...) rhs)
(andmap identifier? (syntax->list #'(var ...)))
(begin
(when (and expr? (not allow-def-after-expr?))
(raise-syntax-error #f "definition after expression" ee))
(syntax-local-bind-syntaxes (syntax->list #'(var ...)) #f intdef)
(loop (stx-cdr x) (cons ee ex) expr?))]
[(define-values . _)
(raise-syntax-error #f "bad define-values form" ee)]
[(define-syntaxes (var ...) rhs)
(andmap identifier? (syntax->list #'(var ...)))
(begin
(when (and expr? (not allow-def-after-expr?))
(raise-syntax-error #f "definition after expression" ee))
(syntax-local-bind-syntaxes (syntax->list #'(var ...))
#'rhs
intdef)
(loop (stx-cdr x) (cons ee ex) expr?))]
[(define-syntaxes . _)
(raise-syntax-error #f "bad define-syntaxes form" ee)]
[_
(loop (stx-cdr x) (cons ee ex) #t)]))]
[(stx-null? x)
(reverse ex)]))))
#| #|
;; Mappings ;; Mappings

View File

@ -2,14 +2,14 @@
@(require scribble/manual @(require scribble/manual
scribble/struct scribble/struct
(for-label stxclass/stxclass)) (for-label macro-debugger/stxclass/stxclass))
@title{Parsing Syntax and Syntax Classes} @title{Parsing Syntax and Syntax Classes}
@defmodule[stxclass/stxclass] @defmodule[macro-debugger/stxclass/stxclass]
@section{Parsing Syntax} @section{Parsing Syntax}
@declare-exporting[stxclass/stxclass] @declare-exporting[macro-debugger/stxclass/stxclass]
@defform/subs[(syntax-parse stx-expr maybe-literals clause ...) @defform/subs[(syntax-parse stx-expr maybe-literals clause ...)
([maybe-literals code:blank ([maybe-literals code:blank
@ -222,7 +222,7 @@ generalized sequences. It may not be used as an expression.
} }
@section{Syntax Classes} @section{Syntax Classes}
@declare-exporting[stxclass/stxclass] @declare-exporting[macro-debugger/stxclass/stxclass]
Syntax classes provide an abstraction mechanism for the specification Syntax classes provide an abstraction mechanism for the specification
of syntax. Basic syntax classes include @scheme[identifier] and of syntax. Basic syntax classes include @scheme[identifier] and
@ -239,30 +239,43 @@ syntax. While the values of the attributes depend on the matched
syntax, the set of attributes and each attribute's ellipsis nesting syntax, the set of attributes and each attribute's ellipsis nesting
depth is fixed for each syntax class. depth is fixed for each syntax class.
@defform*/subs[#:literals (union pattern) @defform*/subs[#:literals (pattern)
[(define-syntax-class name-id stxclass-body) [(define-syntax-class name-id stxclass-option ...
(define-syntax-class (name-id arg-id ...) stxclass-body)] stxclass-variant ...)
([stxclass-body (define-syntax-class (name-id arg-id ...) stxclass-option ...
(union stxclass-body ...) stxclass-variant ...)]
([stxclass-options
(code:line #:description string)
(code:line #:transparent)]
[stxclass-variant
(pattern syntax-pattern pattern-directive ...)])]{ (pattern syntax-pattern pattern-directive ...)])]{
Defines @scheme[name-id] as a syntax class. When the @scheme[arg-id]s Defines @scheme[name-id] as a syntax class. When the @scheme[arg-id]s
are present, they are bound as variables (not pattern variables) in are present, they are bound as variables (not pattern variables) in
the body. the body.
The body of the syntax-class definition specifies the syntax it The body of the syntax-class definition contains one or more variants
accepts and determines the attributes it provides. that specify the syntax it accepts and determines the attributes it
provides. The syntax class provides only those attributes which are
present in every variant. Each such attribute must be defined with the
same ellipsis nesting depth and the same sub-attributes in each
component.
@specsubform[#:literals (union) @specsubform[(code:line #:description string)]{
(union stxclass-body ...)]{
Accepts any syntax accepted by one of the component bodies. Specifies a string to use in error messages involving the syntax
class. For example, if a term is rejected by the syntax class, an
Provides only those attributes which are present in every component error of the form @scheme["expected <description>"] may be generated.
body. Each such attribute must be defined with the same ellipsis
nesting depth and the same sub-attributes in each component.
If absent, the name of the syntax class is used instead.
} }
@specsubform[#:transparent]{
Indicates that errors may be reported with respect to the internal
structure of the syntax class.
}
@specsubform/subs[#:literals (pattern) @specsubform/subs[#:literals (pattern)
(pattern syntax-pattern pattern-directive ...) (pattern syntax-pattern pattern-directive ...)
([stxclass-pattern-directive ([stxclass-pattern-directive
@ -320,17 +333,12 @@ match only proper lists:
} }
@deftogether[( @defidform[pattern]{
@defidform[union]
@defidform[pattern]
)]{
Keywords recognized by @scheme[define-syntax-class]. They may not be
used as expressions.
Keyword recognized by @scheme[define-syntax-class]. It may not be
used as an expression.
} }
@defform[(define-basic-syntax-class (name-id arg-id ...) @defform[(define-basic-syntax-class (name-id arg-id ...)
([attr-id attr-depth] ...) ([attr-id attr-depth] ...)
parser-expr)]{ parser-expr)]{
@ -390,7 +398,7 @@ the @scheme[arg-expr]s) on the syntax object produced by
@section{Library syntax classes} @section{Library syntax classes}
@declare-exporting[stxclass/stxclass] @declare-exporting[macro-debugger/stxclass/stxclass]
@(define-syntax-rule (defstxclass name . pre-flows) @(define-syntax-rule (defstxclass name . pre-flows)
(defidform name . pre-flows)) (defidform name . pre-flows))