一般问题:
我可以racket
从正在运行的 Racket 脚本中调用当前的可执行文件吗?
(system "racket ...")
基本上,如果(find-executable-path "racket")
不返回我当前正在使用的 Racket 可执行文件的路径,我想替换它。
语境:
我真正想要的是尝试编译一些表达式并断言它们会引发编译错误。这是用于单元测试。
一般问题:
我可以racket
从正在运行的 Racket 脚本中调用当前的可执行文件吗?
(system "racket ...")
基本上,如果(find-executable-path "racket")
不返回我当前正在使用的 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
将文件转换为字符串。
对于小型测试,您也可以convert-compile-time-error
从syntax/macro-testing
库中使用。它将导致编译时错误的表达式转换为在评估时引发运行时错误的表达式。表达式使用它在模块中出现的环境,包括本地绑定;您不必摆弄命名空间和eval
.
(check-exn #rx"bad syntax"
(lambda () (convert-compile-time-error (lambda))))
还有convert-syntax-error
(在同一页上)。