有没有办法实现compile-file
的效果但不是磁盘上的常规文件,而是流或内存中的字符串? (即,如果我没有文件并且不想使用此内存数据创建临时文件)
编辑
我正在考虑以下用例:从文件系统以外的其他地方加载代码。例如来自存档(类似于 Java 的 jars 或 Python zip 处理功能)或来自网络。也许有其他方法可以解决这个问题,而不仅仅是弯曲 compile-file
机械。
最佳答案
Rainer Joswig 的第一条评论指出了这一点:
Not in standard Common Lisp.
您可以在每个实现中搜索来自
compile-file
的调用。查看底层实现是否采用流。如果您想自己实现这一点,您将实现一个非常低效的
compile-file
版本。用于生成适合 load
的可加载表单的输入和输出流或您自己的版本。用
with-compilation-unit
包装编译,您必须特别小心 macroexpand
输入顶级表单,请确保 progn
表单被视为顶级表单,locally
, macrolet
和 symbol-macrolet
表单建立绑定(bind)并将其表单处理为具有非空词法环境的顶层(其操作也不可移植),并处理eval-when
表格,其中某些表格可能会被评估、处理或两者兼而有之。然后,生成可外部化的表单,关心什么可以合并,什么不能(例如符号和包),调用 make-load-form
对于 standard-object
, structure-object
和 condition
实例,并特别注意符号和包,例如检查要编译的流是否具有第一个非原子 in-package
在 load
的情况下是否能够发出错误信号使用不同的值 *package*
调用.这只是最小编译的最顶层步骤,或多或少,没有提到编译实际发生的时间(编译时或加载时),
load-time-value
表格和许多细节。有些步骤需要代码遍历。我的建议:只需从压缩数据和套接字中提取并保存您拥有的任何源代码,然后调用
compile-file
后跟 load
, 如果你想保留编译和加载语义。对于更简单的事情,您可以执行以下操作:(let* ((*package* *package*)
(*readtable* *readtable*)
(eof (copy-symbol 'eof))
(form nil))
(loop
(setf form (read stream nil eof))
(when (eq form eof)
(return))
(funcall (compile nil `(lambda () ,form)))))
如果您不太关心可移植性,请让您的实现能够处理压缩文件,例如,向
compile-file
提供解压缩的外部格式。 ,并使您的实现能够打开 URL(URI、IRI,无论您关心什么),而不仅仅是路径名。 AFAIK,ABCL 可以打开 URL 进行输入。然而,compile-file
的输出文件是什么?当使用这样的外部资源调用时?也许自己做compile-and-load
这说明了要同时使用的临时文件 compile-file
的output-file
关键参数和 load
.
关于compiler-construction - 使用内存数据编译文件而不是 Common Lisp 中的真实文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12204947/