编辑:我已经发现了问题,并且找到了解决方法(请参阅最后的更新 2),但似乎应该有一种更优雅的方法来做到这一点——我希望有人能想出一个。
我在尝试使用我使用 Racket/Scribble 的make - at - reader生成的函数时遇到了麻烦我做错了。include/reader
include-at/relative-to/reader
我使用了一些参数来make-at-reader
定义@-forms(基本上是模板系统)的完全不同的用途,基本上是这样的:
(define cmd-readtable
(make-readtable #f #f 'non-terminating-macro <<myExtensionProcHere>>))
(define at-template-reader
(make-at-reader #:syntax? #t
#:inside? #t
#:command-char #\ƒ
#:command-readtable cmd-readtable
#:syntax-post-processor <<myFunctionHere>>))
如果不是超级优雅,我可以在运行时使用call-with-input-file
. 例如,如果我这样做,
((lambda (stx)
(syntax-case stx ()
[(a ...)
#'(string-append a ...)]))
(syntax->list
(call-with-input-file
"/path/to/my/file"
(lambda (in)
(at-template-reader 'test in)))))
我得到类似的东西,
'(string-append "string foo"
"\n"
(expression "bar")
"string baz")
其中,使用eval
and namespace-anchor->namespace
,它应该进行评估。明确地说,所有语法对象都对应于文字字符串或评估为字符串的表达式;但是,外部文件中的表达式确实需要访问模块上下文中的参数和一些其他定义。
但是,我更喜欢使用类似include/reader
or的东西include-at/relative-to/reader
(可能更类似于include/template
from web-server/templates),以便可以在编译时完成解释外部文件的工作。但是,我尝试以at-template-reader
其中一种形式使用 my 完全不成功:更糟糕的是,它们只是运行没有结果,直到内存不足,所以我什至不确定如何调试它们。我想我在这里有点过头了,我会很感激任何人关于如何让它发挥作用的想法。
更新 1: Asumu Takikawa 在评论中询问它是否适用于#:inside? #f
. 我现在已经尝试过了,它确实 - 或者至少更接近于使用 using 的工作,#:inside? #t
在我杀死它或它耗尽内存之前,它只会进入永无止境的土地。#:inside? #f
版本成功并返回值。(它的行为确实与我定义的一些逻辑很奇怪,有时只返回最后一个值,但我认为这可能是因为我做了一些只适用于#:inside? #t
-mode 的假设;我现在正在研究。)
这是否让任何人了解该版本可能出了什么问题#:inside? #t
?我想知道这是否与这样一个事实有关, with #:inside? #t
,它只返回一个表示整个外部文件的语法对象……</p>
更新 2:
我已经确定了这个问题,现在我有一个非常黑客的解决方法,但我希望有人能向我解释正确的方法是什么。
首先,让我给#:inside? #f
我在 Asumu Takikawa 的建议中尝试的函数命名,以便我可以简洁地参考它:
(define at-template-reader-OUTSIDE
(make-at-reader #:syntax? #t
#:inside? #f
#:command-char #\ƒ
#:command-readtable cmd-readtable
#:syntax-post-processor <<myFunctionHere>>))
read-syntax
我正在调用的类似函数at-template-reader
和之间有一个至关重要的区别at-template-reader-OUTSIDE
,这是我通过玩(port->list [r in])
docs发现的(它“返回一个列表,其元素是通过调用r
直到in
它产生 eof 产生的”)。正如预期的那样,每次调用都会at-template-reader-OUTSIDE
产生一个对应于源文件下一个块的语法对象,直到最后一个产生eof
. 然而,每次调用都会at-template-reader
产生一个对应于整个源文件的语法对象,并且永远不会产生eof
——第一次之后的调用只会返回空列表(作为语法对象)。这意味着打电话port->list
——而且,似乎include/reader
还有朋友——永远不会回来。
我已经通过使用包装函数来完成这项工作,如下所示:(在一个模块中,所有内容都处于正确的阶段级别)
(include/reader (file "/path/to/source-file")
(lambda (stx in)
(cond [(eof-object? (peek-char in))
eof]
[else
((lambda (stx)
(syntax-case stx ()
[(a ...)
#'(string-append a ...)]))
(syntax->list
(at-template-reader stx in)))])))
然而,这感觉很笨拙——我希望有人能告诉我这样做的“正确”方法。