167 lines
5.6 KiB
Racket
167 lines
5.6 KiB
Racket
#lang racket/base
|
|
(require (for-syntax racket/base
|
|
"sc.rkt"
|
|
"lib.rkt"
|
|
racket/syntax
|
|
syntax/keyword
|
|
"rep-data.rkt"
|
|
"rep.rkt"
|
|
"kws.rkt")
|
|
"runtime.rkt")
|
|
(provide define-conventions
|
|
define-literal-set
|
|
kernel-literals)
|
|
|
|
(define-syntax (define-conventions stx)
|
|
|
|
(define-syntax-class header
|
|
#:description "name or name with formal parameters"
|
|
(pattern name:id
|
|
#:with formals #'()
|
|
#:attr arity (arity 0 0 null null))
|
|
(pattern (name:id . formals)
|
|
#:attr arity (parse-kw-formals #'formals #:context stx)))
|
|
|
|
(syntax-parse stx
|
|
[(define-conventions h:header rule ...)
|
|
(let ()
|
|
(define rules (check-conventions-rules #'(rule ...) stx))
|
|
(define rxs (map car rules))
|
|
(define dens0 (map cadr rules))
|
|
(define den+defs-list
|
|
(for/list ([den0 (in-list dens0)])
|
|
(let-values ([(den defs) (create-aux-def den0)])
|
|
(cons den defs))))
|
|
(define dens (map car den+defs-list))
|
|
(define defs (apply append (map cdr den+defs-list)))
|
|
|
|
(define/with-syntax (rx ...) rxs)
|
|
(define/with-syntax (def ...) defs)
|
|
(define/with-syntax (parser ...)
|
|
(map den:delayed-parser dens))
|
|
(define/with-syntax (class-name ...)
|
|
(map den:delayed-class dens))
|
|
|
|
#'(begin
|
|
(define-syntax h.name
|
|
(make-conventions
|
|
(quote-syntax get-parsers)
|
|
(lambda ()
|
|
(let ([class-names (list (quote-syntax class-name) ...)])
|
|
(map list
|
|
(list 'rx ...)
|
|
(map make-den:delayed
|
|
(generate-temporaries class-names)
|
|
class-names))))))
|
|
(define get-parsers
|
|
(lambda formals
|
|
def ...
|
|
(list parser ...)))))]))
|
|
|
|
(define-for-syntax (check-phase-level stx ctx)
|
|
(unless (or (exact-integer? (syntax-e stx))
|
|
(eq? #f (syntax-e stx)))
|
|
(raise-syntax-error #f "expected phase-level (exact integer or #f)" ctx stx))
|
|
stx)
|
|
|
|
(define-syntax (define-literal-set stx)
|
|
(syntax-case stx ()
|
|
[(define-literal-set name . rest)
|
|
(let-values ([(chunks rest)
|
|
(parse-keyword-options
|
|
#'rest
|
|
`((#:phase ,check-phase-level)
|
|
(#:for-template)
|
|
(#:for-syntax)
|
|
(#:for-label))
|
|
#:incompatible '((#:phase #:for-template #:for-syntax #:for-label))
|
|
#:context stx
|
|
#:no-duplicates? #t)])
|
|
(unless (identifier? #'name)
|
|
(raise-syntax-error #f "expected identifier" stx #'name))
|
|
(let ([relphase
|
|
(cond [(assq '#:for-template chunks) -1]
|
|
[(assq '#:for-syntax chunks) 1]
|
|
[(assq '#:for-label chunks) #f]
|
|
[else (options-select-value chunks '#:phase #:default 0)])]
|
|
[lits (syntax-case rest ()
|
|
[( (lit ...) )
|
|
(check-literals-list/litset #'(lit ...) stx)]
|
|
[_ (raise-syntax-error #f "bad syntax" stx)])])
|
|
(with-syntax ([((internal external) ...) lits]
|
|
[relphase relphase])
|
|
#`(begin
|
|
(define phase-of-literals
|
|
(if 'relphase
|
|
(+ (phase-of-enclosing-module) 'relphase)
|
|
'relphase))
|
|
(define-syntax name
|
|
(make-literalset
|
|
(list (list 'internal (quote-syntax external)) ...)
|
|
(quote-syntax phase-of-literals)))
|
|
(begin-for-syntax/once
|
|
(for ([x (in-list (syntax->list #'(external ...)))])
|
|
(unless (identifier-binding x 'relphase)
|
|
(raise-syntax-error #f
|
|
(format "literal is unbound in phase ~a" 'relphase)
|
|
(quote-syntax #,stx) x))))))))]))
|
|
|
|
(define-syntax (phase-of-enclosing-module stx)
|
|
(syntax-case stx ()
|
|
[(poem)
|
|
(let ([phase-within-module (syntax-local-phase-level)])
|
|
#`(let ([phase-of-this-expression
|
|
(variable-reference->phase (#%variable-reference))])
|
|
(- phase-of-this-expression
|
|
#,(if (zero? phase-within-module) 0 1))))]))
|
|
|
|
#|
|
|
Literal sets: The goal is for literals to refer to their bindings at
|
|
|
|
phase 0 relative to the enclosing module
|
|
|
|
Use cases, explained:
|
|
1) module X with def-lit-set is required-for-syntax
|
|
phase-of-mod-inst = 1
|
|
phase-of-def = 0
|
|
literals looked up at abs phase 1
|
|
which is phase 0 rel to module X
|
|
2) module X with local def-lit-set within define-syntax
|
|
phase-of-mod-inst = 1 (mod at 0, but +1 within define-syntax)
|
|
phase-of-def = 1
|
|
literals looked up at abs phase 0
|
|
which is phase 0 rel to module X
|
|
3) module X with def-lit-set in phase-2 position (really uncommon case!)
|
|
phase-of-mod-inst = 1 (not 2, apparently)
|
|
phase-of-def = 2
|
|
literals looked up at abs phase 0
|
|
(that's why the weird (if (z?) 0 1) term)
|
|
|#
|
|
|
|
|
|
;; Literal sets
|
|
|
|
(define-literal-set kernel-literals
|
|
(begin
|
|
begin0
|
|
define-values
|
|
define-syntaxes
|
|
define-values-for-syntax
|
|
set!
|
|
let-values
|
|
letrec-values
|
|
#%plain-lambda
|
|
case-lambda
|
|
if
|
|
quote
|
|
quote-syntax
|
|
letrec-syntaxes+values
|
|
with-continuation-mark
|
|
#%expression
|
|
#%plain-app
|
|
#%top
|
|
#%datum
|
|
#%variable-reference
|
|
module #%provide #%require
|
|
#%plain-module-begin))
|