6

有没有办法实现compile-file但不是使用磁盘上的常规文件,而是使用流或仅使用内存中的字符串的效果?(即,如果我没有文件并且不想使用此内存数据创建临时文件)

编辑

我正在考虑以下用例:从文件系统以外的其他地方加载代码。例如来自存档(类似于 Java 的 jars 或 Python zip 处理功能)或来自网络。也许可能有替代方法,而不仅仅是弯曲compile-file机械。

4

1 回答 1

3

Rainer Joswig 的第一条评论指出了这一点:

不在标准的 Common Lisp 中。

您可以在每个实现中搜索来自的调用,compile-file以查看底层实现是否采用流。

如果您想自己实现这一点,您将实现一个非常低效的compile-file输入和输出流版本,它会生成适合load或您自己版本的可加载表单。

用 包装编译with-compilation-unit,您必须特别注意macroexpand顶级表单,确保progn表单被视为顶级表单,locally并且macrolet表单symbol-macrolet建立绑定并将其表单作为顶级表单处理空词法环境(其操作也不是可移植的)和处理eval-when表单,其中一些表单可以被评估、处理或两者兼而有之。然后,生成可外部化的表单,关心什么可以合并,什么不能(例如符号和包),调用make-load-formstandard-object实例structure-objectcondition并特别注意符号和包,例如检查要编译的流是否具有第一个非-原子in-package如果load以不同的值调用*package*.

这只是最小编译的最顶层步骤,或多或少,没有提到编译实际发生的时间(编译时或加载时)、load-time-value表单和许多细节。有些步骤需要代码遍历。

我的建议:只要从压缩数据和套接字中提取并保存您拥有的任何源代码,然后调用compile-fileload如果您想保留编译和加载语义。对于更简单的事情,您可以执行以下操作:

(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-fileoutput-file关键参数和load.

于 2012-09-03T16:17:14.817 回答