在 Racket 脚本中调用 `racket`

Invoke `racket` in a Racket script

一般问题:

我可以从 运行 Racket 脚本中调用当前的 racket 可执行文件吗?

基本上,如果 (find-executable-path "racket") 没有 return 我当前正在使用的 Racket 可执行文件的路径,我想替换 (system "racket ...")

上下文:

我真正想要的是尝试编译一些表达式并断言它们会引发编译错误。这是为了单元测试。

我认为您不需要在此处跳出可执行文件。试试这个:

#lang racket

(require syntax/modread)

;; define a namespace anchor to attach a namespace to:
(define-namespace-anchor anchor)
;; define a namespace for expansion:
(define target-namespace (namespace-anchor->namespace anchor))

(define program-to-compile
  "#lang racket
(+ 3 4)")

;; go ahead and expand
(with-module-reading-parameterization
 (λ()
   (parameterize ([current-namespace target-namespace])
   (expand
    (read-syntax
     "bogus-filename"
     (open-input-string program-to-compile))))))

当我说 Racket 以一种有纪律的方式为 运行 程序提供编译器的能力时,我认为我是正确的。

如果您的目标只是编译一些球拍表达式,您可以使用任何一个 compile or compile-syntax 来实现。示例文件为:

#lang racket
(require rackunit)

(define tests
  (list #'(+ 1 "3")
        #'(void void)
        #'(string-append 4)))

(for/list ([t (in-list test)])
  (check-exn exn:fail?
     (lambda () (compile t))))

其中 exn:fail? 是您要查找的异常。

此外,如果您想要运行测试的一些通用语法上下文,您可以使用#` #,。所以你的代码最终会是这样的:

#lang racket
(require rackunit)

(define tests
  (list #'(+ 1 "3")
        #'(void void)
        #'(string-append 4)))

(for/list ([t (in-list test)])
  (check-exn exn:fail?
     (lambda () (compile #`(module anonymous racket
                             #,t)))))

最后,如果您的代码存储在您的计算机上,您可以使用 John 的解决方案,同时使用 file->string 将文件转换为字符串。

对于小型测试,您还可以使用 syntax/macro-testing 库中的 convert-compile-time-error。它将导致编译时错误的表达式转换为在计算时引发 运行 时错误的表达式。表达式使用它在模块中出现的环境,包括本地绑定;您不必 fiddle 命名空间和 eval.

(check-exn #rx"bad syntax"
            (lambda () (convert-compile-time-error (lambda))))

还有 convert-syntax-error(在同一页上)。