2
votes

I have a small language which is basically an extension of OCaml (actually it is an extension of a subset of OCaml, but that hardly matters). To simplify things I have one "escape" expression that transport OCaml literals into my language (hence you are able to embed arbitrary OCaml code into this language). To compile such an expression to OCaml would simply mean to unwrap the string, but how does one evaluate it?

Of course I understand that OCaml is a statically typed language and how that type system works in general. Hence I also need to be able to provide an environment and inspect the inferred type of the expression (or at least cope with type errors). I am also aware of the need to manage the interpreter state etc. Let's assume for the moment that the embedded expressions are side-effect free.

Obviously this is possible, since both utop and the toplevel are implemented in OCaml themselves. So my first idea was to just pick one of them and adapt them to my needs. Now to my problems:

  • toplevel is obviously part of the main distribution. Although there is a toplevel.mli with the necessary functions and even a .mllib, I cannot find toplevel as packaged library - are there further configuration tweaks needed to get the "interpreter-as-a-library" package?

  • utop seems to do even more strange things. From what I can tell from the sources, it copies some compilerlibs into its source directory at build time. This seems to be quite weird: If it knows at build time how to find these compiler libraries, why not simply link?

So is there any reasonably established way to embed an OCaml interpreter into an OCaml program?

1
Doesn't contain 'compiler-libs.toplevel' what you need?rafix
Indeed.I did not know the precise library name. Could you please make an answer out of this, so I can accept it?choeger
@choeger I think it's okay to do just that yourself. (/me wouldn't want to steal the karma credit, but would appreciate the right answer to be featured nonetheless.)DomQ

1 Answers

1
votes

The easiest way, afaik, is to compile the provided code to a module, using byte code compiler, and then load it with dynlink and execute. You can also compile it by a native compiler, but that will require you to inst.

Update

You can compile your file in any way, including system command, but you also can call directly to the compiler interface [1]:

Compile.implementation Format.std_formatter "test.ml" "test";;

This will create test.cmo and test.cmi files in the same directory with the "test.ml" file. Afterwards, you can load it with Dynlink:

Dynlink.loadfile "test.cmo";;

[1] This module resides somewhere in a compiler-libs library, perhaps "compiler-libs.bytecomp"