caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Joseph Young <ocaml@optimojoe.com>
To: caml-list@inria.fr
Subject: Re: [Caml-list] Two Different Exception Behaviors in camlp4 on the toplevel
Date: Tue, 25 May 2010 08:44:33 +0200 (CEST)	[thread overview]
Message-ID: <Pine.LNX.4.64.1005250839350.10465@myhome> (raw)
In-Reply-To: <AANLkTinxUCinuRgU41QbAq42j-HzsMEfjXGWOiDhmNAs@mail.gmail.com>

 	The type checking using phantom types worked great.  Thanks.  In 
case it helps anyone else, I'm attaching complete working code below.

Joe

----------------------------
$ cat calc.ml
open Camlp4.PreCast;;
module CamlSyntax=
     Camlp4OCamlParser.Make(
         Camlp4OCamlRevisedParser.Make(
             Camlp4.PreCast.Syntax));;

(* The AST for the small calculator *)
type loc=CamlSyntax.Loc.t
type nonterminal=[`Add | `Sub | `Or | `And | `MixedFn];;
type terminal=[`Int of int | `Bool of bool | `Ocaml of (loc*string)];;
type calc=
| Nonterm of loc*nonterminal*(calc list)
| Term of loc*terminal;;

module TypeChecker : sig
     type 'a t
     val add : loc->int t->int t->int t
     val sub : loc->int t->int t->int t
     val or_: loc->bool t->bool t->bool t
     val and_: loc->bool t->bool t->bool t
     val mixed: loc->bool t->int t->int t
     val int_: loc->int -> int t
     val bool_: loc->bool -> bool t
     val expose : 'a t->calc
end = struct
     type 'a t=calc
     let add loc e1 e2 = Nonterm (loc,`Add,[e1;e2])
     let sub loc e1 e2 = Nonterm (loc,`Sub,[e1;e2])
     let or_ loc e1 e2 = Nonterm (loc,`Or,[e1;e2])
     let and_ loc e1 e2 = Nonterm (loc,`And,[e1;e2])
     let mixed loc e1 e2 = Nonterm (loc,`MixedFn,[e1;e2])
     let int_ loc i = Term (loc,`Int i)
     let bool_ loc b = Term (loc,`Bool b)
     let expose e=e
end;;

open TypeChecker;;

(* Grammar for a simple calculator *)
module CalcGram = Camlp4.PreCast.MakeGram(Camlp4.PreCast.Lexer);;
let (term:calc CalcGram.Entry.t)= CalcGram.Entry.mk "term";;
let term_eoi = CalcGram.Entry.mk "Simple calculator quotation";;
EXTEND CalcGram
     GLOBAL: term term_eoi;
     term:
     [ "alg"
         [ e1 = SELF; "+"; e2 = SELF -> Nonterm(_loc,`Add,[e1;e2])
         | e1 = SELF; "-"; e2 = SELF -> Nonterm(_loc,`Sub,[e1;e2])]
     | "bool"
         [ e1 = SELF; "or"; e2 = SELF -> Nonterm(_loc,`Or,[e1;e2])
         | e1 = SELF; "and"; e2 = SELF -> Nonterm(_loc,`And,[e1;e2])]
     | "other"
         [ e1 = SELF; "mix"; e2= SELF -> Nonterm(_loc,`MixedFn,[e1;e2])]
     | "simple"
         [ "$"; `STRING (e,_); "$" -> Term(_loc,`Ocaml (_loc,e))
         | `INT (i, _)  -> Term(_loc,`Int i)
         | "true" -> Term(_loc,`Bool true)
         | "false" -> Term(_loc,`Bool false)
         | "("; e = term; ")" -> e ]
     ];
     term_eoi:
     [[ t = term; `EOI -> t ]];
END;;

(* Generates an expression with the location information *)
let expr_of_loc _loc=
     let (a, b, c, d, e, f, g, h) = CamlSyntax.Loc.to_tuple _loc in
     <:expr< Loc.of_tuple ($`str:a$, $`int:b$, $`int:c$, $`int:d$,
         $`int:e$, $`int:f$, $`int:g$, $`bool:h$) >>
;;

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

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

(* 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 rec to_expr e=
         match e with
         | Nonterm (_loc,name,[e1;e2]) ->
             let constr= expr_of_nonterm _loc name in
             let e1=to_expr e1 in
             let e2=to_expr e2 in
             <:expr< $constr$ $expr_of_loc _loc$ $e1$ $e2$>>
         | Term (_loc,data) ->
             let data= expr_of_term _loc data in
             <:expr< $data$ >>
         | _ -> failwith ("Wrong number of arguments.")
     in
     to_expr e
;;

let expand_calc_quot loc lopt e= to_expr loc e;;

Syntax.Quotation.add "calc" Syntax.Quotation.DynAst.expr_tag 
expand_calc_quot;;

----------------------------

$  cat Makefile
all:
         ocamlc -c -I +camlp4 -I +camlp4/Camlp4Parsers -pp camlp4of -o 
calc.cmo calc.ml

----------------------------


  reply	other threads:[~2010-05-25  7:08 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 ` [Caml-list] " blue storm
2010-05-25  6:44   ` Joseph Young [this message]
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=Pine.LNX.4.64.1005250839350.10465@myhome \
    --to=ocaml@optimojoe.com \
    --cc=caml-list@inria.fr \
    /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).