Version française
Home     About     Download     Resources     Contact us    
Browse thread
Re: Caml typed AST
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: oleg@o...
Subject: Re: Caml typed AST

Martin Potier wrote:
> I'd like to know if there is a way to retrieve a typped AST from Caml.

The function read_type_exp : string -> Typedtree.expression
takes a string of OCaml code, parses it, typechecks and returns the
typed tree. For example, evaluating

let test1 = read_type_exp "let x = 21 and twice y = 2 * y in twice x";;

prints

val test1 : Typedtree.expression =
  {Typedtree.exp_desc =
    Typedtree.Texp_let (Asttypes.Nonrecursive,
     [({Typedtree.pat_desc = Typedtree.Tpat_var <abstr>;
        Typedtree.pat_loc =
         {Location.loc_start =
           {Lexing.pos_fname = ""; Lexing.pos_lnum = 1; Lexing.pos_bol = 0;
            Lexing.pos_cnum = 4};
          Location.loc_end =
           {Lexing.pos_fname = ""; Lexing.pos_lnum = 1; Lexing.pos_bol = 0;
            Lexing.pos_cnum = 5};
          Location.loc_ghost = false};
        Typedtree.pat_type =
         {Types.desc =
           Types.Tlink
            {Types.desc =
              Types.Tconstr (Path.Pident <abstr>, [],
               {contents = Types.Mnil});
             Types.level = 100000000; Types.id = 649};
          Types.level = 59; Types.id = 647};
        Typedtree.pat_env = <abstr>},
       {Typedtree.exp_desc = Typedtree.Texp_constant (Asttypes.Const_int 21);
        Typedtree.exp_loc =
         {Location.loc_start =
           {Lexing.pos_fname = ""; Lexing.pos_lnum = 1; Lexing.pos_bol = 0;
            Lexing.pos_cnum = 8};
          Location.loc_end =
           {Lexing.pos_fname = ""; Lexing.pos_lnum = 1; Lexing.pos_bol = 0;
            Lexing.pos_cnum = 10};
          Location.loc_ghost = false};
        Typedtree.exp_type =
         {Types.desc =
           Types.Tconstr (Path.Pident <abstr>, [], {contents = Types.Mnil});
          Types.level = 100000000; Types.id = 649};
        Typedtree.exp_env = <abstr>});
...plus many more lines....

(and this is only the part that corresponds let x = 21). As you can
see (although probably not easily) the type-checker has figured
out that both x and 21 have the type int. The module
typing/printtyp.mli in the OCaml distribution has a few nicer printing
functions.

Here is the code (top-level script)

(* In the directory directives below, replace
   /usr/ports/lang/ocaml/work/ocaml-3.11.1/
 with the complete path to your ocaml distribution.
 It is assumed the directory contains the made OCaml.
*)

#directory "/usr/ports/lang/ocaml/work/ocaml-3.11.1/parsing";;
#directory "/usr/ports/lang/ocaml/work/ocaml-3.11.1/typing";;
#directory "/usr/ports/lang/ocaml/work/ocaml-3.11.1/toplevel";;
#directory "/usr/ports/lang/ocaml/work/ocaml-3.11.1/utils";;


(* Please do NOT change the order of the following directives! *)
(* This must be loaded first! It is stateful, and affects Predef *)
#load "ident.cmo";; 

(* Load the rest of the compiler *)
#load "misc.cmo";;
#load "path.cmo";;
#load "types.cmo";;
#load "btype.cmo";;
#load "tbl.cmo";;
#load "subst.cmo";;
#load "predef.cmo";;
#load "datarepr.cmo";;
#load "config.cmo";;
#load "consistbl.cmo";;
#load "clflags.cmo";;
#load "env.cmo";;
#load "ctype.cmo";;
#load "printast.cmo";;
#load "oprint.cmo";;
#load "primitive.cmo";;
#load "printtyp.cmo";;

#load "linenum.cmo";;
#load "warnings.cmo";;
#load "location.cmo";;

#load "typetexp.cmo";;
#load "includecore.cmo";;
#load "typedecl.cmo";;
#load "typedtree.cmo";;
#load "stypes.cmo";;
#load "parmatch.cmo";;
#load "typecore.cmo";;
#load "includeclass.cmo";;
#load "typeclass.cmo";;
#load "mtype.cmo";;
#load "includemod.cmo";;
#load "longident.cmo";;
#load "typemod.cmo";;

#load "ccomp.cmo";;
#load "lexer.cmo";;
#load "syntaxerr.cmo";;
#load "parser.cmo";;
#load "parse.cmo";;


(* from driver/compile.ml *)
let initial_env () =
  Config.load_path := [""; "/usr/local/lib/ocaml"];
  Env.reset_cache ();
  Ident.reinit();
  try
    Env.open_pers_signature "Pervasives" Env.initial
  with Not_found ->
    failwith "cannot open pervasives.cmi"
;;

let env = initial_env()
;;

(* toplevel/toploop.ml *)

let read_type_exp src_string =
  let lb = Lexing.from_string src_string in
  match Parse.implementation lb  with
  | [{Parsetree.pstr_desc = Parsetree.Pstr_eval exp}] ->
      Ctype.init_def(Ident.current_time()); 
      Typecore.reset_delayed_checks ();
      let texp = Typecore.type_expression env exp
      in Typecore.force_delayed_checks (); texp
  | _ -> failwith "Only expressions are expected"
;;

let test1 = read_type_exp "let x = 21 and twice y = 2 * y in twice x";;