initial cut at HtDP languages via #lang; syntax/module-reader: split compiled-module info from reader info, reorganize and complete docs, don't export read-properties or get-info-getter for now
svn: r18759
This commit is contained in:
parent
d436f1deb3
commit
b559c9db9b
10
collects/htdp/asl/lang/reader.ss
Normal file
10
collects/htdp/asl/lang/reader.ss
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#lang s-exp syntax/module-reader
|
||||||
|
lang/htdp-advanced
|
||||||
|
#:read (wrap-reader read options)
|
||||||
|
#:read-syntax (wrap-reader read-syntax options)
|
||||||
|
#:info (make-info options)
|
||||||
|
#:module-info (make-module-info options)
|
||||||
|
|
||||||
|
(require htdp/bsl/reader)
|
||||||
|
(define options '(abbreviate-cons-as-list
|
||||||
|
read-accept-quasiquote))
|
10
collects/htdp/bsl+/lang/reader.ss
Normal file
10
collects/htdp/bsl+/lang/reader.ss
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#lang s-exp syntax/module-reader
|
||||||
|
lang/htdp-beginner-abbr
|
||||||
|
#:read (wrap-reader read options)
|
||||||
|
#:read-syntax (wrap-reader read-syntax options)
|
||||||
|
#:info (make-info options)
|
||||||
|
#:module-info (make-module-info options)
|
||||||
|
|
||||||
|
(require htdp/bsl/reader)
|
||||||
|
(define options '(abbreviate-cons-as-list
|
||||||
|
read-accept-quasiquote))
|
9
collects/htdp/bsl/lang/reader.ss
Normal file
9
collects/htdp/bsl/lang/reader.ss
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#lang s-exp syntax/module-reader
|
||||||
|
lang/htdp-beginner
|
||||||
|
#:read (wrap-reader read options)
|
||||||
|
#:read-syntax (wrap-reader read-syntax options)
|
||||||
|
#:info (make-info options)
|
||||||
|
#:module-info (make-module-info options)
|
||||||
|
|
||||||
|
(require htdp/bsl/reader)
|
||||||
|
(define options '())
|
8
collects/htdp/bsl/module-info.ss
Normal file
8
collects/htdp/bsl/module-info.ss
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#lang scheme/base
|
||||||
|
(provide module-info)
|
||||||
|
|
||||||
|
(define ((module-info options) key default)
|
||||||
|
(case key
|
||||||
|
[(configure-runtime) `#(htdp/bsl/runtime configure ,options)]
|
||||||
|
[else default]))
|
||||||
|
|
18
collects/htdp/bsl/reader.ss
Normal file
18
collects/htdp/bsl/reader.ss
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#lang scheme/base
|
||||||
|
(provide wrap-reader
|
||||||
|
make-info
|
||||||
|
make-module-info)
|
||||||
|
|
||||||
|
(define (wrap-reader read-proc options)
|
||||||
|
(lambda args
|
||||||
|
(parameterize ([read-decimal-as-inexact #f]
|
||||||
|
[read-accept-dot #f]
|
||||||
|
[read-accept-quasiquote (memq 'read-accept-quasiquote options)])
|
||||||
|
(apply read-proc args))))
|
||||||
|
|
||||||
|
(define ((make-info options) key default use-default)
|
||||||
|
(case key
|
||||||
|
[else (use-default key default)]))
|
||||||
|
|
||||||
|
(define (make-module-info options)
|
||||||
|
`#(htdp/bsl/module-info module-info ,options))
|
41
collects/htdp/bsl/runtime.ss
Normal file
41
collects/htdp/bsl/runtime.ss
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#lang scheme/base
|
||||||
|
(require mzlib/pconvert
|
||||||
|
scheme/pretty
|
||||||
|
lang/private/set-result)
|
||||||
|
|
||||||
|
(provide configure)
|
||||||
|
|
||||||
|
(define (configure options)
|
||||||
|
;; Set print-convert options:
|
||||||
|
(booleans-as-true/false #t)
|
||||||
|
(constructor-style-printing #t)
|
||||||
|
(abbreviate-cons-as-list (memq 'abbreviate-cons-as-list options))
|
||||||
|
(current-print-convert-hook
|
||||||
|
(let ([ph (current-print-convert-hook)])
|
||||||
|
(lambda (val basic sub)
|
||||||
|
(cond
|
||||||
|
[(equal? val set!-result) '(void)]
|
||||||
|
[else (ph val basic sub)]))))
|
||||||
|
(use-named/undefined-handler
|
||||||
|
(lambda (x)
|
||||||
|
(and (memq 'use-function-output-syntax options)
|
||||||
|
(procedure? x)
|
||||||
|
(object-name x))))
|
||||||
|
(named/undefined-handler
|
||||||
|
(lambda (x)
|
||||||
|
(string->symbol
|
||||||
|
(format "function:~a" (object-name x)))))
|
||||||
|
;; Set pretty-print options:
|
||||||
|
(pretty-print-show-inexactness #t)
|
||||||
|
(pretty-print-exact-as-decimal #t)
|
||||||
|
|
||||||
|
;; Set print handlers to use print-convert and pretty-print:
|
||||||
|
(current-print
|
||||||
|
(lambda (v)
|
||||||
|
(unless (void? v)
|
||||||
|
(pretty-print (print-convert v)))))
|
||||||
|
(global-port-print-handler
|
||||||
|
(lambda (val port [depth 0])
|
||||||
|
(let ([val (print-convert val)])
|
||||||
|
(parameterize ([pretty-print-columns 'infinity])
|
||||||
|
(pretty-print val port depth))))))
|
10
collects/htdp/isl+/lang/reader.ss
Normal file
10
collects/htdp/isl+/lang/reader.ss
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#lang s-exp syntax/module-reader
|
||||||
|
lang/htdp-intermediate-lambda
|
||||||
|
#:read (wrap-reader read options)
|
||||||
|
#:read-syntax (wrap-reader read-syntax options)
|
||||||
|
#:info (make-info options)
|
||||||
|
#:module-info (make-module-info options)
|
||||||
|
|
||||||
|
(require htdp/bsl/reader)
|
||||||
|
(define options '(abbreviate-cons-as-list
|
||||||
|
read-accept-quasiquote))
|
10
collects/htdp/isl/lang/reader.ss
Normal file
10
collects/htdp/isl/lang/reader.ss
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#lang s-exp syntax/module-reader
|
||||||
|
lang/htdp-intermediate
|
||||||
|
#:read (wrap-reader read options)
|
||||||
|
#:read-syntax (wrap-reader read-syntax options)
|
||||||
|
#:info (make-info options)
|
||||||
|
#:module-info (make-module-info options)
|
||||||
|
|
||||||
|
(require htdp/bsl/reader)
|
||||||
|
(define options '(abbreviate-cons-as-list
|
||||||
|
read-accept-quasiquote))
|
|
@ -6,13 +6,8 @@ scribble/base/lang
|
||||||
#:read-syntax scribble:read-syntax-inside
|
#:read-syntax scribble:read-syntax-inside
|
||||||
#:whole-body-readers? #t
|
#:whole-body-readers? #t
|
||||||
#:wrapper1 (lambda (t) (list* 'doc 'values '() (t)))
|
#:wrapper1 (lambda (t) (list* 'doc 'values '() (t)))
|
||||||
#:info
|
#:module-info (scribble-base-module-info)
|
||||||
(lambda (key defval default)
|
#:info (scribble-base-info)
|
||||||
(case key
|
|
||||||
[(color-lexer)
|
|
||||||
(dynamic-require 'syntax-color/scribble-lexer 'scribble-inside-lexer)]
|
|
||||||
[(drscheme:toolbar-buttons)
|
|
||||||
(dynamic-require 'scribble/tools/drscheme-buttons 'drscheme-buttons)]
|
|
||||||
[else (default key defval)]))
|
|
||||||
|
|
||||||
(require (prefix-in scribble: "../../reader.ss"))
|
(require (prefix-in scribble: "../../reader.ss")
|
||||||
|
"../reader.ss")
|
||||||
|
|
17
collects/scribble/base/reader.ss
Normal file
17
collects/scribble/base/reader.ss
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#lang scheme/base
|
||||||
|
|
||||||
|
(provide scribble-base-info
|
||||||
|
scribble-base-module-info)
|
||||||
|
|
||||||
|
(define (scribble-base-info)
|
||||||
|
(lambda (key defval default)
|
||||||
|
(case key
|
||||||
|
[(color-lexer)
|
||||||
|
(dynamic-require 'syntax-color/scribble-lexer 'scribble-inside-lexer)]
|
||||||
|
[(drscheme:toolbar-buttons)
|
||||||
|
(dynamic-require 'scribble/tools/drscheme-buttons 'drscheme-buttons)]
|
||||||
|
[else (default key defval)])))
|
||||||
|
|
||||||
|
(define (scribble-base-module-info)
|
||||||
|
(lambda (modpath data)
|
||||||
|
#f))
|
|
@ -1,19 +1,13 @@
|
||||||
#lang scheme/base
|
#lang s-exp syntax/module-reader
|
||||||
(require (prefix-in doc: scribble/doc/reader))
|
|
||||||
(provide (rename-out [doc:read read]
|
|
||||||
[my:read-syntax read-syntax])
|
|
||||||
get-info)
|
|
||||||
|
|
||||||
(define (my:read-syntax . args)
|
scribble/doclang
|
||||||
(let ([s (apply doc:read-syntax args)])
|
|
||||||
;; For now, remove the 'module-language property added by `doc:read-syntax'
|
|
||||||
(syntax-property s 'module-language #f)))
|
|
||||||
|
|
||||||
(define (get-info . args)
|
#:read scribble:read-inside
|
||||||
(lambda (key defval)
|
#:read-syntax scribble:read-syntax-inside
|
||||||
(case key
|
#:whole-body-readers? #t
|
||||||
[(color-lexer)
|
#:wrapper1 (lambda (t) (list* 'doc 'values '() (t)))
|
||||||
(dynamic-require 'syntax-color/scribble-lexer 'scribble-inside-lexer)]
|
#:module-info (scribble-base-module-info)
|
||||||
[(drscheme:toolbar-buttons)
|
#:info (scribble-base-info)
|
||||||
(dynamic-require 'scribble/tools/drscheme-buttons 'drscheme-buttons)]
|
|
||||||
[else defval])))
|
(require (prefix-in scribble: "../../reader.ss")
|
||||||
|
scribble/base/reader)
|
||||||
|
|
|
@ -1,10 +1 @@
|
||||||
#lang s-exp syntax/module-reader
|
#lang scheme/base
|
||||||
|
|
||||||
scribble/doclang
|
|
||||||
|
|
||||||
#:read scribble:read-inside
|
|
||||||
#:read-syntax scribble:read-syntax-inside
|
|
||||||
#:whole-body-readers? #t
|
|
||||||
#:wrapper1 (lambda (t) (list* 'doc 'values '() (t)))
|
|
||||||
|
|
||||||
(require (prefix-in scribble: "../reader.ss"))
|
|
||||||
|
|
|
@ -6,10 +6,8 @@ scribble/jfp/lang
|
||||||
#:read-syntax scribble:read-syntax-inside
|
#:read-syntax scribble:read-syntax-inside
|
||||||
#:whole-body-readers? #t
|
#:whole-body-readers? #t
|
||||||
#:wrapper1 (lambda (t) (cons 'doc (t)))
|
#:wrapper1 (lambda (t) (cons 'doc (t)))
|
||||||
#:info (lambda (key defval default)
|
#:module-info (scribble-base-module-info)
|
||||||
(case key
|
#:info (scribble-base-info)
|
||||||
[(color-lexer)
|
|
||||||
(dynamic-require 'syntax-color/scribble-lexer 'scribble-inside-lexer)]
|
|
||||||
[else (default key defval)]))
|
|
||||||
|
|
||||||
(require (prefix-in scribble: "../../reader.ss"))
|
(require (prefix-in scribble: "../../reader.ss")
|
||||||
|
scribble/base/reader)
|
||||||
|
|
|
@ -5,5 +5,8 @@ scribble/lp/lang/lang
|
||||||
#:read read-inside
|
#:read read-inside
|
||||||
#:read-syntax read-syntax-inside
|
#:read-syntax read-syntax-inside
|
||||||
#:whole-body-readers? #t
|
#:whole-body-readers? #t
|
||||||
|
#:module-info (scribble-base-module-info)
|
||||||
|
#:info (scribble-base-info)
|
||||||
|
|
||||||
(require scribble/reader)
|
(require scribble/reader
|
||||||
|
scribble/base/reader)
|
||||||
|
|
|
@ -6,12 +6,8 @@ scribble/manual/lang
|
||||||
#:read-syntax scribble:read-syntax-inside
|
#:read-syntax scribble:read-syntax-inside
|
||||||
#:whole-body-readers? #t
|
#:whole-body-readers? #t
|
||||||
#:wrapper1 (lambda (t) (cons 'doc (t)))
|
#:wrapper1 (lambda (t) (cons 'doc (t)))
|
||||||
#:info (lambda (key defval default)
|
#:module-info (scribble-base-module-info)
|
||||||
(case key
|
#:info (scribble-base-info)
|
||||||
[(color-lexer)
|
|
||||||
(dynamic-require 'syntax-color/scribble-lexer 'scribble-inside-lexer)]
|
|
||||||
[(drscheme:toolbar-buttons)
|
|
||||||
(dynamic-require 'scribble/tools/drscheme-buttons 'drscheme-buttons)]
|
|
||||||
[else (default key defval)]))
|
|
||||||
|
|
||||||
(require (prefix-in scribble: "../../reader.ss"))
|
(require (prefix-in scribble: "../../reader.ss")
|
||||||
|
scribble/base/reader)
|
||||||
|
|
|
@ -41,9 +41,11 @@
|
||||||
#f
|
#f
|
||||||
(list (hash-lang)
|
(list (hash-lang)
|
||||||
spacer
|
spacer
|
||||||
(as-modname-link
|
,(if (identifier? #'lang)
|
||||||
|
`(as-modname-link
|
||||||
',#'lang
|
',#'lang
|
||||||
(to-element ',#'lang)))))
|
(to-element ',#'lang))
|
||||||
|
#'(scheme lang)))))
|
||||||
#'lang)]
|
#'lang)]
|
||||||
[(file ...)
|
[(file ...)
|
||||||
(if (syntax-e #'filename)
|
(if (syntax-e #'filename)
|
||||||
|
|
|
@ -6,10 +6,8 @@ scribble/sigplan/lang
|
||||||
#:read-syntax scribble:read-syntax-inside
|
#:read-syntax scribble:read-syntax-inside
|
||||||
#:whole-body-readers? #t
|
#:whole-body-readers? #t
|
||||||
#:wrapper1 (lambda (t) (cons 'doc (t)))
|
#:wrapper1 (lambda (t) (cons 'doc (t)))
|
||||||
#:info (lambda (key defval default)
|
#:module-info (scribble-base-module-info)
|
||||||
(case key
|
#:info (scribble-base-info)
|
||||||
[(color-lexer)
|
|
||||||
(dynamic-require 'syntax-color/scribble-lexer 'scribble-inside-lexer)]
|
|
||||||
[else (default key defval)]))
|
|
||||||
|
|
||||||
(require (prefix-in scribble: "../../reader.ss"))
|
(require (prefix-in scribble: "../../reader.ss")
|
||||||
|
scribble/base/reader)
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
[#:wrapper2 ~wrapper2 #'#f]
|
[#:wrapper2 ~wrapper2 #'#f]
|
||||||
[#:whole-body-readers? ~whole-body-readers? #'#f]
|
[#:whole-body-readers? ~whole-body-readers? #'#f]
|
||||||
[#:info ~info #'#f]
|
[#:info ~info #'#f]
|
||||||
|
[#:module-info ~module-get-info #'#f]
|
||||||
[(when (equal? (and lang #t) (and ~lang #t))
|
[(when (equal? (and lang #t) (and ~lang #t))
|
||||||
(err (string-append
|
(err (string-append
|
||||||
"must specify either a module language, or #:language"
|
"must specify either a module language, or #:language"
|
||||||
|
@ -57,7 +58,7 @@
|
||||||
#,@body
|
#,@body
|
||||||
(#%provide (rename lang:read read)
|
(#%provide (rename lang:read read)
|
||||||
(rename lang:read-syntax read-syntax)
|
(rename lang:read-syntax read-syntax)
|
||||||
read-properties get-info-getter get-info)
|
get-info)
|
||||||
(define (lang:read in modpath line col pos)
|
(define (lang:read in modpath line col pos)
|
||||||
(wrap-internal/wrapper #f #f in modpath line col pos))
|
(wrap-internal/wrapper #f #f in modpath line col pos))
|
||||||
(define (lang:read-syntax src in modpath line col pos)
|
(define (lang:read-syntax src in modpath line col pos)
|
||||||
|
@ -83,9 +84,12 @@
|
||||||
[(ar? w2 3) (w2 in rd stx?)]
|
[(ar? w2 3) (w2 in rd stx?)]
|
||||||
[else (w2 in rd)])])
|
[else (w2 in rd)])])
|
||||||
(if stx?
|
(if stx?
|
||||||
(syntax-property r
|
(let ([prop #,(if (syntax-e ~module-get-info)
|
||||||
'module-language
|
~module-get-info
|
||||||
(vector (syntax->datum modpath) 'get-info-getter props))
|
#'#f)])
|
||||||
|
(if prop
|
||||||
|
(syntax-property r 'module-language prop)
|
||||||
|
r))
|
||||||
r)))
|
r)))
|
||||||
(define read-properties (lang->read-properties #,~lang))
|
(define read-properties (lang->read-properties #,~lang))
|
||||||
(define (get-info in modpath line col pos)
|
(define (get-info in modpath line col pos)
|
||||||
|
@ -95,7 +99,7 @@
|
||||||
(define data (cadr props))
|
(define data (cadr props))
|
||||||
(define (default-info what defval)
|
(define (default-info what defval)
|
||||||
(case what
|
(case what
|
||||||
[(module-language) (car props)]
|
[(module-language) lang]
|
||||||
;; ... more?
|
;; ... more?
|
||||||
[else defval]))
|
[else defval]))
|
||||||
(define info
|
(define info
|
||||||
|
|
|
@ -5,168 +5,286 @@
|
||||||
(only-in scribble/reader
|
(only-in scribble/reader
|
||||||
read-syntax-inside read-inside)))
|
read-syntax-inside read-inside)))
|
||||||
|
|
||||||
|
@(begin
|
||||||
|
(define-syntax-rule (define-mb name)
|
||||||
|
(begin
|
||||||
|
(require (for-label scheme/base))
|
||||||
|
(define name @scheme[#%module-begin])))
|
||||||
|
(define-mb scheme-#%module-begin))
|
||||||
|
|
||||||
@title[#:tag "module-reader"]{Module Reader}
|
@title[#:tag "module-reader"]{Module Reader}
|
||||||
|
|
||||||
@defmodule[syntax/module-reader]
|
@defmodule[syntax/module-reader]
|
||||||
|
|
||||||
The @schememodname[syntax/module-reader] language provides support for
|
The @schememodname[syntax/module-reader] library provides support for
|
||||||
defining @hash-lang[] readers. In its simplest form, the only thing
|
defining @hash-lang[] readers. It is normally used as a module
|
||||||
that is needed in the body of a @schememodname[syntax/module-reader]
|
language, though it may also be @scheme[require]d to get
|
||||||
is the name of the module that will be used in the language position
|
@scheme[make-meta-reader]. It provides all of the bindings of
|
||||||
of read modules; using keywords, the resulting readers can be
|
@scheme[scheme/base] other than @|scheme-#%module-begin|.
|
||||||
customized in a number of ways.
|
|
||||||
|
|
||||||
@defform*/subs[
|
@defform*/subs[
|
||||||
[(#%module-begin module-path)
|
[(#%module-begin module-path)
|
||||||
(#%module-begin module-path reader-option ... body ....)
|
(#%module-begin module-path reader-option ... form ....)
|
||||||
(#%module-begin reader-option ... body ....)]
|
(#%module-begin reader-option ... form ....)]
|
||||||
([reader-option (code:line #:language lang-expr)
|
([reader-option (code:line #:read read-expr)
|
||||||
(code:line #:read read-expr)
|
|
||||||
(code:line #:read-syntax read-syntax-expr)
|
(code:line #:read-syntax read-syntax-expr)
|
||||||
(code:line #:info info-expr)
|
(code:line #:whole-body-readers? whole?-expr)
|
||||||
(code:line #:wrapper1 wrapper1-expr)
|
(code:line #:wrapper1 wrapper1-expr)
|
||||||
(code:line #:wrapper2 wrapper2-expr)
|
(code:line #:wrapper2 wrapper2-expr)
|
||||||
(code:line #:whole-body-readers? whole?-expr)])]{
|
(code:line #:language lang-expr)
|
||||||
|
(code:line #:info info-expr)
|
||||||
|
(code:line #:module-info module-info-expr)])
|
||||||
|
#:contracts ([read-expr (input-port? . -> . any/c)]
|
||||||
|
[read-syntax-expr (any/c input-port? . -> . any/c)]
|
||||||
|
[whole-expr any/c]
|
||||||
|
[wrapper1-expr (or/c ((-> any/c) . -> . any/c)
|
||||||
|
((-> any/c) boolean? . -> . any/c))]
|
||||||
|
[wrapper2-expr (or/c (input-port? (input-port? . -> . any/c)
|
||||||
|
. -> . any/c)
|
||||||
|
(input-port? (input-port? . -> . any/c)
|
||||||
|
boolean? . -> . any/c))]
|
||||||
|
[info-expr (symbol? any/c (symbol? any/c . -> . any/c) . -> . any/c)]
|
||||||
|
[module-info-expr (or/c (vector/c module-path? symbol? any/c) #f)]
|
||||||
|
[lang-expr (or/c module-path?
|
||||||
|
(and/c syntax? (compose module-path? syntax->datum))
|
||||||
|
procedure?)])]{
|
||||||
|
|
||||||
Causes a module written in the @schememodname[syntax/module-reader]
|
In its simplest form, the body of a module written with
|
||||||
language to define and provide @schemeidfont{read} and
|
@schememodname[syntax/module-reader] contains just a module path,
|
||||||
@schemeidfont{read-syntax} functions, making the module an
|
which is used in the language position of read modules. For example, a
|
||||||
implementation of a reader. In particular, the exported reader
|
module @scheme[_something]@scheme[/lang/reader] implemented as
|
||||||
functions read all S-expressions until an end-of-file, and package
|
|
||||||
them into a new module in the @scheme[module-path] language.
|
|
||||||
|
|
||||||
That is, a module @scheme[_something]@scheme[/lang/reader] implemented
|
|
||||||
as
|
|
||||||
|
|
||||||
@schemeblock[
|
@schemeblock[
|
||||||
(module reader syntax/module-reader
|
(module reader @#,schememodname[syntax/module-reader]
|
||||||
module-path)
|
module-path)
|
||||||
]
|
]
|
||||||
|
|
||||||
creates a reader that converts @scheme[#,(hash-lang)_something] into
|
creates a reader such that a module source
|
||||||
|
|
||||||
|
@schememod[
|
||||||
|
@#,scheme[_something]
|
||||||
|
....
|
||||||
|
]
|
||||||
|
|
||||||
|
is read as
|
||||||
|
|
||||||
@schemeblock[
|
@schemeblock[
|
||||||
(module _name-id module-path
|
(module _name-id module-path
|
||||||
(#%module-begin ....))
|
(#%module-begin ....))
|
||||||
]
|
]
|
||||||
|
|
||||||
where @scheme[_name-id] is derived from the name of the port used by
|
Keyword-based @scheme[reader-option]s allow further customization, as
|
||||||
the reader, or @scheme[anonymous-module] if the port has no name.
|
listed below. Additional @scheme[form]s are as in the body of
|
||||||
|
@scheme[scheme/base] module; they can import bindings and define
|
||||||
|
identifiers used by the @scheme[reader-option]s.
|
||||||
|
|
||||||
For example, @scheme[scheme/base/lang/reader] is implemented as
|
@itemlist[
|
||||||
|
|
||||||
@schemeblock[
|
@item{@scheme[#:read] and @scheme[#:read-syntax] (both or neither
|
||||||
|
must be supplied) specify alternate readers for parsing the
|
||||||
|
module body---replacements @scheme[read] and
|
||||||
|
@scheme[read-syntax], respectively. Normally, the replacements
|
||||||
|
for @scheme[read] and @scheme[read-syntax] are applied
|
||||||
|
repeatedly to the module source until @scheme[eof] is produced,
|
||||||
|
but see also @scheme[#:whole-body-readers?].
|
||||||
|
|
||||||
|
For example, a language built on the @secref[#:doc '(lib
|
||||||
|
"scribblings/honu/honu.scrbl")]{Honu} reader could be
|
||||||
|
implemented with:
|
||||||
|
|
||||||
|
@schemeblock[
|
||||||
(module reader syntax/module-reader
|
(module reader syntax/module-reader
|
||||||
scheme/base)
|
module-path
|
||||||
]
|
|
||||||
|
|
||||||
The reader functions can be customized in a number of ways, using
|
|
||||||
keyword markers in the syntax of the reader module. A @scheme[#:read]
|
|
||||||
and @scheme[#:read-syntax] keywords can be used to specify functions
|
|
||||||
other than @scheme[read] and @scheme[read-syntax] to perform the
|
|
||||||
reading. For example, you can implement a
|
|
||||||
@secref[#:doc '(lib "scribblings/honu/honu.scrbl")]{Honu} reader
|
|
||||||
using:
|
|
||||||
|
|
||||||
@schemeblock[
|
|
||||||
(module reader syntax/module-reader
|
|
||||||
honu
|
|
||||||
#:read read-honu
|
#:read read-honu
|
||||||
#:read-syntax read-honu-syntax)
|
#:read-syntax read-honu-syntax)
|
||||||
]
|
]
|
||||||
|
|
||||||
Similarly, the @scheme[#:info] keyword supplies a procedure to be used
|
See also @scheme[#:wrapper1] and @scheme[#:wrapper2], which
|
||||||
by a @scheme[get-info] export (see @scheme[read-language]). The
|
support simple parameterization of readers rather than
|
||||||
procedure produced by @scheme[info-expr] should consume three
|
wholesale replacement.}
|
||||||
arguments: a key value, a default result, and a default info-getting
|
|
||||||
procedure (to be called with the key and default result for default
|
|
||||||
handling). If @scheme[#:info] is not supplied, the default
|
|
||||||
info-getting procedure is used.
|
|
||||||
|
|
||||||
You can also use the (optional) module @scheme[body] forms to provide
|
@item{@scheme[#:whole-body-readers?] specified as true indicates that
|
||||||
more definitions that might be needed to implement your reader
|
the @scheme[#:read] and @scheme[#:read-syntax] functions each produce a
|
||||||
functions. For example, here is a case-insensitive reader for the
|
list of S-expressions or syntax objects for the module content,
|
||||||
@scheme[scheme/base] language:
|
so that each is applied just once to the input stream.
|
||||||
|
|
||||||
@schemeblock[
|
If the resulting list contains a single form that starts with
|
||||||
(module reader syntax/module-reader
|
the symbol @scheme['#%module-begin] (or a syntax object whose
|
||||||
scheme/base
|
datum is that symbol), then the first item is used as the
|
||||||
#:read (wrap read) #:read-syntax (wrap read-syntax)
|
module body; otherwise, a @scheme['#%module-begin] (symbol or
|
||||||
(define ((wrap reader) . args)
|
identifier) is added to the beginning of the list to form the
|
||||||
(parameterize ([read-case-sensitive #f]) (apply reader args))))
|
module body.}
|
||||||
]
|
|
||||||
|
|
||||||
In many cases, however, the standard @scheme[read] and
|
@item{@scheme[#:wrapper1] specifies a function that controls the
|
||||||
@scheme[read-syntax] are fine, as long as you can customize the
|
dynamic context in which the @scheme[read] and
|
||||||
dynamic context they're invoked at. For this, @scheme[#:wrapper1] can
|
@scheme[read-syntax] functions are called. A
|
||||||
specify a function that can control the dynamic context in which the
|
@scheme[#:wrapper1]-specified function must accept a thunk, and
|
||||||
reader functions are called. It should evaluate to a function that
|
it normally calls the thunk to produce a result while
|
||||||
consumes a thunk and invokes it in the right context. Here is an
|
@scheme[parameterizing] the call. Optionally, a
|
||||||
alternative definition of the case-insensitive language using
|
@scheme[#:wrapper1]-specified function can accept a boolean
|
||||||
@scheme[#:wrapper1]:
|
that indicates whether it is used in @scheme[read]
|
||||||
|
(@scheme[#f]) or @scheme[read-syntax] (@scheme[#t]) mode.
|
||||||
|
|
||||||
@schemeblock[
|
For example, a language like @scheme[scheme/base] but with
|
||||||
|
case-insensitive reading of symbols and identifiers can be
|
||||||
|
implemented as
|
||||||
|
|
||||||
|
@schemeblock[
|
||||||
(module reader syntax/module-reader
|
(module reader syntax/module-reader
|
||||||
scheme/base
|
scheme/base
|
||||||
#:wrapper1 (lambda (t)
|
#:wrapper1 (lambda (t)
|
||||||
(parameterize ([read-case-sensitive #f])
|
(parameterize ([read-case-sensitive #f])
|
||||||
(t))))
|
(t))))
|
||||||
|
]
|
||||||
|
|
||||||
|
Using a @tech[#:doc refman]{readtable}, you can implement
|
||||||
|
languages that are extensions of plain S-expressions.}
|
||||||
|
|
||||||
|
@item{@scheme[#:wrapper2] is like @scheme[#:wrapper1], but a
|
||||||
|
@scheme[#:wrapper2]-specified function receives the input port
|
||||||
|
to be read, and the function that it receives accepts an input
|
||||||
|
port (usually, but not necessarily the same input port). A
|
||||||
|
@scheme[#:wrapper2]-specified function can optionally accept an
|
||||||
|
boolean that indicates whether it is used in @scheme[read]
|
||||||
|
(@scheme[#f]) or @scheme[read-syntax] (@scheme[#t]) mode.}
|
||||||
|
|
||||||
|
@item{@scheme[#:info] specifies an implementation of reflective
|
||||||
|
information that is used by external tools to manipulate the
|
||||||
|
@emph{source} of modules in the language @scheme[_something]. For
|
||||||
|
example, DrScheme uses information from @scheme[#:info] to
|
||||||
|
determine the style of syntax coloring that it should use for
|
||||||
|
editing a module's source.
|
||||||
|
|
||||||
|
The @scheme[#:info] specification should be a function of three
|
||||||
|
arguments: a symbol indicating the kind of information
|
||||||
|
requested (as defined by external tools), a default value that
|
||||||
|
normally should be returned if the symbol is not recognized,
|
||||||
|
and a default-filtering function that takes the first two
|
||||||
|
arguments and returns a result.
|
||||||
|
|
||||||
|
The expression after @scheme[#:info] is placed into a context
|
||||||
|
where @scheme[language-module] and @scheme[language-data] are
|
||||||
|
bound. The @scheme[language-module] identifier is bound to the
|
||||||
|
@scheme[module-path] that is used for the read module's
|
||||||
|
language as written directly or as determined through
|
||||||
|
@scheme[#:language]. The @scheme[language-data] identifier is
|
||||||
|
bound to the second result from @scheme[#:language], or
|
||||||
|
@scheme[#f] by default.
|
||||||
|
|
||||||
|
The default-filtering function passed to the @scheme[#:info]
|
||||||
|
function is intended to provide support for information that
|
||||||
|
@schememodname[syntax/module-reader] can provide automatically.
|
||||||
|
Currently, it recognizes only the @scheme['module-language]
|
||||||
|
key, for which it returns @scheme[language-module]; it returns
|
||||||
|
the given default value for any other key.
|
||||||
|
|
||||||
|
In the case of the DrScheme syntax-coloring example, DrScheme
|
||||||
|
supplies @scheme['color-lexer] as the symbol argument, and it
|
||||||
|
supplies @scheme[#f] as the default. The default-filtering
|
||||||
|
argument (i.e., the third argument to the @scheme[#:info]
|
||||||
|
function) currently just returns the default for
|
||||||
|
@scheme['color-lexer].}
|
||||||
|
|
||||||
|
@item{@scheme[#:module-info] specifies an implementation of
|
||||||
|
reflective information that is used by external tools to
|
||||||
|
manipulate the @emph{compiled} form of modules in the language
|
||||||
|
@scheme[_something]. For example, when MzScheme starts a
|
||||||
|
program, it uses information attached to the compiled main
|
||||||
|
module to initialize the run-time environment.
|
||||||
|
|
||||||
|
Since the compiled form exists at a different time than when
|
||||||
|
the source is read, a @scheme[#:module-info] specification is a
|
||||||
|
vector that indicates an implementation of the reflective
|
||||||
|
information, instead of a direct implementation as a function
|
||||||
|
like @scheme[#:info]. The first element of the vector is a
|
||||||
|
module path, the second is a symbol corresponding to a function
|
||||||
|
exported from the module, and the last element is a value to be
|
||||||
|
passed to the function. The last value in the vector must be
|
||||||
|
one that can be written with @scheme[write] and read back with
|
||||||
|
@scheme[read]. When the exported function indicated by the
|
||||||
|
first two vector elements is called with the value from the
|
||||||
|
last vector element, the result should be a function or two
|
||||||
|
arguments: a symbol and a default value. The symbol and default
|
||||||
|
value are used as for the @scheme[#:info] function (but without
|
||||||
|
an extra default-filtering function).
|
||||||
|
|
||||||
|
The value specified by @scheme[#:module-info] is attached to
|
||||||
|
the @scheme[module] form that is parsed from source through the
|
||||||
|
@scheme['module-language] syntax property. See @scheme[module]
|
||||||
|
for more information.
|
||||||
|
|
||||||
|
The expression after @scheme[#:module-info] is placed into a
|
||||||
|
context where @scheme[language-module] are
|
||||||
|
@scheme[language-data] are bound, the same as for
|
||||||
|
@scheme[#:info].
|
||||||
|
|
||||||
|
In the case of the MzScheme run-time configuration example,
|
||||||
|
MzScheme uses the @scheme[#:module-info] vector to obtain a
|
||||||
|
function, and then it passes @scheme['configure-runtime] to the
|
||||||
|
function to obtain information about configuring the runtime
|
||||||
|
environment. See also @secref[#:doc refman "configure-runtime"].}
|
||||||
|
|
||||||
|
@item{@scheme[#:language] allows the language of the read
|
||||||
|
@scheme[module] to be computed dynamically and based on the
|
||||||
|
program source, instead of using a constant
|
||||||
|
@scheme[module-path]. (Either @scheme[#:language] or
|
||||||
|
@scheme[module-path] must be provided, but not both.)
|
||||||
|
|
||||||
|
This value of the @scheme[#:language] option can be either a
|
||||||
|
module path (possibly as a syntax object) that is used as a
|
||||||
|
module language, or it can be a procedure. If it is a procedure
|
||||||
|
it can accept either
|
||||||
|
|
||||||
|
@itemlist[
|
||||||
|
@item{0 arguments;}
|
||||||
|
@item{1 argument: an input port; or}
|
||||||
|
@item{5 arguments: an input port, a syntax object whose datum
|
||||||
|
is a module path for the enclosing module as it was
|
||||||
|
referenced through @hash-lang[] or
|
||||||
|
@schememetafont{#reader}, a starting line number
|
||||||
|
(positive exact integer) or @scheme[#f], a column
|
||||||
|
number (non-negative exact integer) or @scheme[#f], and
|
||||||
|
a position number (positive exact integer) or
|
||||||
|
@scheme[#f].}
|
||||||
|
]
|
||||||
|
|
||||||
|
The result can be either
|
||||||
|
|
||||||
|
@itemlist[
|
||||||
|
@item{a single value, which is a module path or a syntax
|
||||||
|
object whose datum is a module path, to be used
|
||||||
|
like @scheme[module-path]; or}
|
||||||
|
@item{two values, where the first is like a single-value
|
||||||
|
result and the second can be any value.}
|
||||||
|
]
|
||||||
|
|
||||||
|
The second result, which defaults to @scheme[#f] if only a
|
||||||
|
single result is produced, is made available to the
|
||||||
|
@scheme[#:info] and @scheme[#:module-info] functions through
|
||||||
|
the @scheme[language-data] binding. For example, it can be a
|
||||||
|
specification derived from the input stream that changes the
|
||||||
|
module's reflective information (such as the syntax-coloring
|
||||||
|
mode or the output-printing styles).}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
Note that using a @tech[#:doc refman]{readtable}, you can implement
|
As another example, the following reader defines a ``language'' that
|
||||||
languages that are extensions of plain S-expressions.
|
ignores the contents of the file, and simply reads files as if they
|
||||||
|
were empty:
|
||||||
|
|
||||||
In addition to this wrapper, there is also @scheme[#:wrapper2] that
|
|
||||||
has more control over the resulting reader functions. If specified,
|
|
||||||
this wrapper is handed the input port and a (one-argumet) reader
|
|
||||||
function that expects the input port as an argument. This allows this
|
|
||||||
wrapper to hand a different port value to the reader function, for
|
|
||||||
example, it can divert the read to use different file (if given a port
|
|
||||||
that corresponds to a file). Here is the case-insensitive implemented
|
|
||||||
using this option:
|
|
||||||
|
|
||||||
@schemeblock[
|
|
||||||
(module reader syntax/module-reader
|
|
||||||
scheme/base
|
|
||||||
#:wrapper2 (lambda (in r)
|
|
||||||
(parameterize ([read-case-sensitive #f])
|
|
||||||
(r in))))
|
|
||||||
]
|
|
||||||
|
|
||||||
In some cases, the reader functions read the whole file, so there is
|
|
||||||
no need to iterate them (e.g., Scribble's @scheme[read-inside] and
|
|
||||||
@scheme[read-syntax-inside]). In these cases you can specify
|
|
||||||
@scheme[#:whole-body-readers?] as @scheme[#t] --- the readers are
|
|
||||||
expected to return a list of expressions in this case.
|
|
||||||
|
|
||||||
In addition, the two wrappers can return a different value than the
|
|
||||||
wrapped function. This introduces two more customization points for
|
|
||||||
the resulting readers:
|
|
||||||
@itemize[
|
|
||||||
@item{The thunk that is passed to a @scheme[#:wrapper1] function
|
|
||||||
reads the file contents and returns a list of read expressions
|
|
||||||
(either syntax values or S-expressions). For example, the
|
|
||||||
following reader defines a ``language'' that ignores the contents
|
|
||||||
of the file, and simply reads files as if they were empty:
|
|
||||||
@schemeblock[
|
@schemeblock[
|
||||||
(module ignored syntax/module-reader
|
(module ignored syntax/module-reader
|
||||||
scheme/base
|
scheme/base
|
||||||
#:wrapper1 (lambda (t) (t) '()))]
|
#:wrapper1 (lambda (t) (t) '()))]
|
||||||
Note that it is still performing the read, otherwise the module
|
|
||||||
loader will complain about extra expressions.}
|
Note that the wrapper still performs the read, otherwise the module
|
||||||
@item{The reader function that is passed to a @scheme[#:wrapper2]
|
loader would complain about extra expressions.
|
||||||
function returns the final reault of the reader (a module
|
|
||||||
expression). You can return a different value, for example,
|
As a more useful example, the following module language is similar to
|
||||||
making it use a different language module.}]
|
@schememodname[at-exp], where the first datum in the file determines
|
||||||
In some rare cases, it is more convenient to know whether a reader is
|
the actual language (which means that the library specification is
|
||||||
invoked for a @scheme[read] or for a @scheme[read-syntax]. To
|
effectively ignored):
|
||||||
accommodate these cases, both wrappers can accept an additional
|
|
||||||
argument, and in this case, they will be handed a boolean value that
|
|
||||||
indicates whether the reader is expected to read syntax (@scheme[#t])
|
|
||||||
or not (@scheme[#f]). For example, here is a reader that uses the
|
|
||||||
scribble syntax, and the first datum in the file determines the actual
|
|
||||||
language (which means that the library specification is effectively
|
|
||||||
ignored):
|
|
||||||
@schemeblock[
|
@schemeblock[
|
||||||
(module reader syntax/module-reader
|
(module reader syntax/module-reader
|
||||||
-ignored-
|
-ignored-
|
||||||
|
@ -186,7 +304,7 @@ ignored):
|
||||||
(require scribble/reader))
|
(require scribble/reader))
|
||||||
]
|
]
|
||||||
|
|
||||||
This ability to change the language position in the resulting module
|
The ability to change the language position in the resulting module
|
||||||
expression can be useful in cases such as the above, where the base
|
expression can be useful in cases such as the above, where the base
|
||||||
language module is chosen based on the input. To make this more
|
language module is chosen based on the input. To make this more
|
||||||
convenient, you can omit the @scheme[module-path] and instead specify
|
convenient, you can omit the @scheme[module-path] and instead specify
|
||||||
|
@ -210,15 +328,9 @@ concisely:
|
||||||
(require scribble/reader))
|
(require scribble/reader))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
For such cases, however, the alternative reader constructor
|
||||||
Note: if such whole-body reader functions return a list with a single
|
@scheme[make-meta-reader] implements a might tightly controlled
|
||||||
expression that begins with @scheme[#%module-begin], then the
|
reading of the module language.}
|
||||||
@scheme[syntax/module-reader] language will not inappropriately add
|
|
||||||
another. This for backwards-compatibility with older code: having a
|
|
||||||
whole-body reader functions or wrapper functions that return a
|
|
||||||
@scheme[#%module-begin]-wrapped body is deprectaed.
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@defproc[(make-meta-reader [self-sym symbol?]
|
@defproc[(make-meta-reader [self-sym symbol?]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user