caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: oleg@okmij.org
To: martin.potier@gmail.com
Cc: caml-list@inria.fr
Subject: Re: Caml typed AST
Date: Wed,  9 Jun 2010 00:47:03 -0700 (PDT)	[thread overview]
Message-ID: <20100609074703.E3754173BB@Adric.ern.nps.edu> (raw)


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";;


             reply	other threads:[~2010-06-09  7:51 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-06-09  7:47 oleg [this message]
  -- strict thread matches above, loose matches on Subject: below --
2010-06-08 21:29 Martin Potier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20100609074703.E3754173BB@Adric.ern.nps.edu \
    --to=oleg@okmij.org \
    --cc=caml-list@inria.fr \
    --cc=martin.potier@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).