为新语言导入 Beautiful Racket reader?

Importing Beautiful Racket reader for new language?

我正在使用 Beautiful Racket to draft a new DSL, bleir, based on s-expressions. I first install a new racket package using the Master Recipe

raco pkg new bleir
cd bleir
raco pkg install

然后我在 madatory 文件中设置了一个残留的 reader 和扩展器,main.rkt:

#lang br/quicklang

(module+ reader
  (provide read-syntax)
  (require br/quicklang))

(provide (rename-out [bleir-expander #%module-begin]))
(define-macro (bleir-expander PARSE-TREE)
  #'(#%module-begin
     (display PARSE-TREE)))

然后我写了一个测试文件,tyst-bleir.rkt[故意拼写错误,以回避字符串名称“test”的潜在问题]:

#lang bleir
42

我遇到问题:

Module Language: only a module expression is allowed, either
    #lang <language-name>
 or
    (module <name> <language> ...)
 in: 42

我可以用两种方式修复它,“恶心”和“神秘”。首先,令人作呕的修复,在 tyst-bleir.rkt:

(module tyst-bleir bleir
  42)

这有效,从 br/quicklang 和我的自定义扩展器调用双重导出的 reader,显示 42

问题 1#lang bleir 语法应该 与冗长的 (module ...) 语法相同它不是?为什么 #lang bleir 无法从 br/quicklang 导入 reader?

现在,神秘的修复:

#lang s-exp bleir
42

这显然使用了模块(包?)s-exp 中的替代 s-exp reader,我猜没问题。至少我没有被屏蔽。但是,我不明白为什么我不能以相同的方式使用 br/quicklang 中的 reader。

#lang br/quicklang bleir
42
bleir: unbound identifier in: bleir

问题 2:为什么这不起作用?我可以修好吗?如果是,怎么做?

这是另一个失败的尝试,从另一个方向尝试从 s-exp 导入 main-rkt 中的 reader:

(module+ reader
  (provide read-syntax)
  (require s-exp))
main.rkt:11:11: cannot open module file
  module path: s-exp
  path: /usr/share/racket/collects/s-exp/main.rkt
  system error: no such file or directory; rkt_err=3 in: s-exp
  no package suggestions are available .

问题 3: 为什么这不起作用?我可以修好吗?如果是,怎么做?

问题 1

您没有完全按照您参考的主配方进行操作。如果您继续阅读,您将看到:

read-syntax must return one value: code for a module expres­sion, repre­sented as a syntax object. Typi­cally, the converted S-expres­sions from the source file are inserted into this syntax object. This syntax object must have no iden­ti­fier bind­ings. This module code must include a refer­ence to the expander that will provide the initial set of bind­ings when the module code is eval­u­ated. In pseudocode:

#lang br
(module reader br
  (provide read-syntax)
  (define (read-syntax name port)
    (define s-exprs (read-code-from port))
    (strip-bindings
     #`(module dsl-mod-name dsl/expander
         #,@s-exprs))))

换句话说,您的 read-syntax 需要 return (strip-bindings #'(module ...))

问题 2

我认为您混淆了“用户使用的语言”和“语言设计者使用的语言”。

“用户使用的语言”类似于 #lang bleir#lang slideshow#lang pollen 等。这些语言提供了执行特定领域任务的结构。例如,#lang slideshow 是一种用于创建演示文稿的语言。 #lang pollen 是一种用于创建书籍的语言。

“语言设计者使用的语言”是一种“用户使用的语言”,这里的用户就是语言设计者。这些语言提供了使语言创建更容易的结构。 #lang br/quicklang 属于此类。

因此,作为语言设计者,您会在 bleir/main.rkt 内部使用 #lang br/quicklang 来构建语言 bleir。但是您的用户不是语言设计者,不需要编写(甚至不需要知道)#lang br/quicklang.


主配方谈到了两件事:reader 和扩展器。在完全开发的语言中,您将同时提供 reader 和扩展器。 s-exp 可以看作是“运行”非完全开发的语言的方便 hack 语言,这些语言只有扩展器,但还没有 reader。

所以,#lang s-exp bleir 工作的原因是你有一个功能扩展器,所以 #lang s-exp bleir 使用你的扩展器但完全忽略你的 reader 子模块。 #lang bleir 不起作用的原因是您的 reader 子模块有问题(请参阅问题 1)。 #lang br/quicklang bleir 不起作用的原因是用户写 #lang br/quicklang.

没有任何意义

我建议您忘记 s-exp 并修复您的 reader。 AFAIK,Beautiful Racket 并没有真正谈论 s-exp,如果您正在阅读本书,使用 s-exp 只会让您感到困惑。

问题 3

如果您需要技术解答,https://docs.racket-lang.org/guide/hash-lang_syntax.html (or more generally https://docs.racket-lang.org/reference/reader.html#%28part._parse-reader%29) 回答您的问题:

Unlike racket, s-exp cannot be used as a module path with require. Although the syntax of language for #lang overlaps with the syntax of module paths, a language is not used directly as a module path. Instead, a language obtains a module path by trying two locations: first, it looks for a reader submodule of the main module for language. If this is not a valid module path, then language is suffixed with /lang/reader. (If neither is a valid module path, an error is raised.) The resulting module supplies read and read-syntax functions using a protocol that is similar to the one for #reader.