Freek Wiedijk
Freek Wiedijk

Reputation: 511

Opening modules from the OCaml compiler without building a custom toplevel

I would like to have a few lines of code at the start of my OCaml input file to have toplevel remember the last expression typed all the time, under the name of it. I.e., I want to have:

# 3 + 4;;
val it : int = 7
# it;;
val it : int = 7
# let foo = 42;;
val foo : int = 42
# it + 130;;
val it : int = 137
#

But I don't want to build a custom toplevel or use camlp5 or anything fancy like that.

What I currently do (in OCaml version 4.02.3, I don't know why I have that version; but I hope the exact version doesn't matter?) is the following:

#directory "+compiler-libs";;

#load "/opt/src/ocaml-4.02.3/utils/warnings.cmo";;
#load "/opt/src/ocaml-4.02.3/parsing/location.cmo";;

let convert_phrase x =
  match x with
  | Parsetree.Ptop_def
        [{Parsetree.pstr_desc = Parsetree.Pstr_eval (e, a)}] ->
      Parsetree.Ptop_def
        ([{Parsetree.pstr_desc =
             Parsetree.Pstr_value (Asttypes.Nonrecursive,
               [{Parsetree.pvb_pat =
                   {Parsetree.ppat_desc =
                      Parsetree.Ppat_var (Location.mknoloc "it");
                    Parsetree.ppat_loc = Location.none;
                    Parsetree.ppat_attributes = []};
                 Parsetree.pvb_expr = e;
                 Parsetree.pvb_attributes = a;
                 Parsetree.pvb_loc = Location.none}]);
           Parsetree.pstr_loc = Location.none}])
  | x -> x;;

Toploop.parse_toplevel_phrase :=
  let parse_toplevel_phrase = !Toploop.parse_toplevel_phrase in
  fun x -> convert_phrase (parse_toplevel_phrase x);;

And that kind of works.

My question: if I just do the #directory "+compiler-libs";; thing, I can access the Toploop and Parsetree modules, but I cannot access the Location module! What is the reason for that? I find having to load .cmo files from my source directories very unattractive.

So is there a way to do what I want without having to have a source tree available?

Or, in other words: why the difference between Toploop and Location, in this respect?

Upvotes: 3

Views: 281

Answers (1)

camlspotter
camlspotter

Reputation: 9040

In short, what you should load is not individual .cmo files but

#load "ocamlcommon.cma";;

which is in +compiler-libs directory.

The differences between Parsetree, Toploop and Location are subtle...

In OCaml, data types and their constructors become accessible only with adding its directory to the load path (by #directory "<dir>"). No object code loading (by #load) is required for them.

Parsetree is so called "mli only module": it has only data type definitions and no values are defined. Therefore everything in Parsetree is accessible only by putting it into the load path.

Location defines types and values. Its data types and constructors are accessible without loading the object file but values require the loading. In this case, the object location.cmo is loaded when you load ocamlcommon.cma which archives it.

Toploop is a tricky one. You can access the values of Toploop even without loading toploop.cmo, since Toploop is linked and already available in OCaml toplevel.

Upvotes: 8

Related Questions