关于动态编译:一个OCaml程序,用于检查OCaml代码是否编译

An OCaml program for checking if OCaml code compiles

我想编写一个具有 compile 函数的 OCaml 模块,该函数将接受一个包含 OCaml 程序的字符串并将编译结果输出为正确或错误,在错误情况下,将输出有关行和字符的信息的第一个错误。我不关心错误是什么(至少现在是这样)。

一个基本的模块类型是:

1
2
3
4
5
module type Compile =
    sig
        type result = Correct | Error of (int*int)
        val compile : string -> result
    end

至少有两种完全不同的实现方式:

  • 快速破解方式——将程序中的字符串写入文件,使用Unix进程在命令行调用ocamlc并解析stderr;
  • 正确的方法——使用 OCaml 工具来分析代码。
  • 关于 (1),我无法获取 stderr 的内容。我开始使用
    Unix.open_process_in,它将标准输出重定向到我可以读取的 in_channel。
    由于 ocamlc 输出的编译错误转到标准错误(而不是标准输出),我尝试使用

    1
    let ic = Unix.open_process_in"ocamlc test.ml 2>&1"

    以便 stderr 的内容在命令行被重定向到 stdout。这样,我希望,ic
    将包含编译错误。不幸的是,情况并非如此,ic 仅包含 End_of_file.

    然后我转到 Unix.create_process 命令,因为它允许我为 out、in、err 选择新通道。但是我在选择这些频道时遇到了麻烦。输出通道应该是什么,以便我可以在我的程序中读取它?

    关于(2),您认为(合理)简单的方法是什么?

    非常感谢您的帮助!


    关于 2),OCaml 安装通常有一个 compiler-lib 目录,其中包含许多组成编译器的模块,包括解析器。这没有记录,但可用于进行编译和类型检查。对于解析,还有 Camlp4,它可以用来做除了预处理之外的事情(我想你可以将 Camlp4 加载到你的程序中并将它用作库,可能在对其进行一些修补之后),但它只包含语法而不是类型检查器。


    关于 1) 我认为你做错了什么。在我的机器上:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    > ocaml unix.cma
            Objective Caml version 3.12.0

    # let ic = Unix.open_process_in"ocamlc test.ml 2>&1";;
    val ic : in_channel =
    # input_line ic;;
    - : string ="File "test.ml", line 1, characters 0-1:"
    # input_line ic;;
    - : string ="Error: I/O error: test.ml: No such file or directory"
    # input_line ic;;
    Exception: End_of_file.

    For Unix.create_process 一种方法是将 Unix.stdin 传递给 new_stdout 以便您可以通过程序的标准输入读取进程的输出(假设您不想使用其他程序的标准输入)。
    但我更简单的方法是使用 Unix.open_process_full.

    关于 2) 你可以尝试使用 toplevellib.cma (但是请注意,这是完全没有文档且不受支持的)。查看发行版中的 toplevel/toploop.mli,尤其是 Toploop.execute_phrase.