caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: blue storm <bluestorm.dylc@gmail.com>
To: Joseph Young <ocaml@optimojoe.com>
Cc: caml-list@inria.fr
Subject: Re: [Caml-list] Two Different Exception Behaviors in camlp4 on the  toplevel
Date: Mon, 24 May 2010 09:35:50 +0200	[thread overview]
Message-ID: <AANLkTinxUCinuRgU41QbAq42j-HzsMEfjXGWOiDhmNAs@mail.gmail.com> (raw)
In-Reply-To: <Pine.LNX.4.64.1005240532130.6622@myhome>

The reason you have two different kinds of error is that you use
type_ast in two different places :

  (* Converts a calculator AST into an OCaml AST *)
  let to_expr base_loc prog=
     let e=CalcGram.parse_string term_eoi base_loc prog in
     let _= type_ast e in
     let rec to_expr e= ... in
     let e= to_expr e in ...
     <:expr< let _ = type_ast $e$ in $e$ >>
  ;;

The first occurence of "type_ast" in that code is executed at
parsing-time. The second occurence, inside <:expr< ... >>, is executed
at runtime, like a classical OCaml exception, and the toplevel does no
special error reporting on Camlp4-related exceptions.

You could fix this by inserting (at runtime) a call to the Camlp4
exception printer :
   <:expr< let _ =
             try type_ast $e$ with exn ->
               Format.eprintf "%a@." Camlp4.ErrorHandler.print exn;
               raise exn in
           $e$ >>

Unfortunately, I'm not sure it will work in the toplevel (wich has a
special location handling as there is no "file" associated to
locations). It will work however if you #use a file containing an
erroneous code.

$ cat foo.ml
open Camlp4.PreCast
open Calc
let _ = <:calc< 1 + (2 + $"<:calc< true >>"$) >>

$ ocamlc -pp 'camlp4o calc.cmo' -I +camlp4 dynlink.cma camlp4lib.cma
calc.cmo foo.ml -o foo
$ ./foo
File "foo.ml", line 3, characters 21-45:
Camlp4: Uncaught exception: Calc.Type_error
Fatal error: exception Loc.Exc_located(_, _)

$ ocaml dynlink.cma camlp4o.cma calc.cmo
# #use "foo.ml";;
File "foo.ml", line 3, characters 21-45:
Camlp4: Uncaught exception: Calc.Type_error
Exception: Loc.Exc_located (<abstr>, Calc.Type_error).




You are actually doing unecessary work. The OCaml type system being
quite powerful, it is easy to have it doing the work, instead of
coding your own limited typechecker. The idea is that you should only
generate OCaml terms that are typed exactly when you want them to be
typed.

(** We use a RuntimeCalc module with a typed interface to enforce correct types
    for calc values *)
module RuntimeCalc : sig
  type calc =
      [ `Nonterm of [ `Add | `Sub | `Or | `And ] * calc list
      | `Term of [ `Int of int | `Bool of bool ] ]
  type 'a t
  val add : int t list -> int t
  val sub : int t list -> int t
  val or_ : bool t list -> bool t
  val and_ : bool t list -> bool t
  val int : int -> int t
  val bool : bool -> bool t
  val expose : 'a t -> calc
end = struct
  type calc =
      [ `Nonterm of [ `Add | `Sub | `Or | `And ] * calc list
      | `Term of [ `Int of int | `Bool of bool ] ]
  type 'a t = calc
  let expose calc = calc
  let op name li = `Nonterm (name, li)
  let add li = op `Add li
  let sub li = op `Sub li
  let and_ li = op `And li
  let or_ li = op `Or li
  let int n = `Term (`Int n)
  let bool b = `Term (`Bool b)
  let expose t = t
end

(* Generates an expression with the nonterminal information *)
let expr_of_nonterm _loc e=
   match e with
   | `Add -> <:expr< RuntimeCalc.add >>
   | `Sub -> <:expr< RuntimeCalc.sub >>
   | `Or -> <:expr< RuntimeCalc.or_ >>
   | `And -> <:expr< RuntimeCalc.and_ >>
;;

(* Generates an expression with the terminal information *)
let expr_of_term _loc e=
   match e with
   | `Int i -> <:expr< RuntimeCalc.int $`int:i$ >>
   | `Bool b -> <:expr< RuntimeCalc.bool $`bool:b$ >>
   | `Ocaml(l,e) -> Gram.parse_string Syntax.expr_eoi l e
;;

(* Converts a calculator AST into an OCaml AST *)
let to_expr _loc prog =
   let rec to_expr : calc -> Ast.expr = function
     | `Nonterm (_loc, name, nodes) ->
         let nodes= expr_of_list _loc (List.map to_expr nodes) in
         let name = expr_of_nonterm _loc name in
         <:expr< $name$ $nodes$ >>
     | `Term(_loc, term) ->
         expr_of_term _loc term in
   let e = to_expr (CalcGram.parse_string term_eoi _loc prog) in
   <:expr< $e$ >>
;;

In that example, I put RuntimeCalc inside the Calc module for
convenience (and similarity with your code). You should really put it
outside, in a separated module, and keep a strong separation between
camlp4-time code and runtime code.


  reply	other threads:[~2010-05-24  7:35 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-05-24  3:46 Joseph Young
2010-05-24  7:35 ` blue storm [this message]
2010-05-25  6:44   ` [Caml-list] " Joseph Young
2010-05-25  7:28     ` blue storm

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=AANLkTinxUCinuRgU41QbAq42j-HzsMEfjXGWOiDhmNAs@mail.gmail.com \
    --to=bluestorm.dylc@gmail.com \
    --cc=caml-list@inria.fr \
    --cc=ocaml@optimojoe.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).