caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Camlp4 type constructor transformation
@ 2011-03-14 19:32 eagriffis
  2011-03-23  8:57 ` Hendrik Tews
  0 siblings, 1 reply; 2+ messages in thread
From: eagriffis @ 2011-03-14 19:32 UTC (permalink / raw)
  To: caml-list

Hello,

I am having trouble getting Camlp4 to detect and transform type constructors
that take parameters. I believe the problem is with my grammar. Here is a base
case (call it base.ml):


open Camlp4.PreCast
open Syntax

let is_interesting = function
  | ("Foo", 2) -> true
  | _ -> false
    
let rec name = function
  | Ast.ExApp (_, e, _) -> name e
  | Ast.ExId (_, Ast.IdUid (_, n)) -> n
  | _ -> raise Not_found
;;

let arity e =
  (* print_string "ZZZ\t";
  let _loc = Loc.ghost in
  Printers.OCaml.print_implem <:str_item< $exp:e$ >>; *)
  let rec loop a = function
    | Ast.ExApp (_, f, _) -> loop (a + 1) f
    | Ast.ExId (_, Ast.IdUid _) -> a
    | _ -> raise Not_found
  in
  loop 0 e

let apply _loc e1 e2 =
  try
    (* Printf.printf "XXX\t%s %d\n" (name e1) (arity e1); *)
    if is_interesting (name e1, arity e1) then
      <:expr< transform ($e1$ $e2$) >>
    else
      <:expr< $e1$ $e2$ >>
  with Not_found -> <:expr< $e1$ $e2$ >>

DELETE_RULE Gram expr: SELF; SELF END;

EXTEND Gram
  GLOBAL: expr;

  expr: LEVEL "apply"
    [ LEFTA
	[ e1 = SELF; e2 = SELF -> apply _loc e1 e2 ] ];
  
END;;


I compile with this command (ocaml 3.12.0):

ocamlc -I +camlp4 -pp camlp4of dynlink.cma camlp4fulllib.cma base.ml


Here is a test case (call it test.ml):

type t = Foo of int * int | Bar of int | Baz
    
let f = function
  | 1 -> Foo (1, 1)
  | 2 -> Bar 2
  | _ -> Baz


I process the test case with this command:

camlp4of base.cmo test.ml


... and get the following output:

type t = | Foo of int * int | Bar of int | Baz

let f = function | 1 -> Foo ((1, 1)) | 2 -> Bar 2 | _ -> Baz


... but what I want is this:

type t = | Foo of int * int | Bar of int | Baz

let f = function | 1 -> transform (Foo (1, 1)) | 2 -> Bar 2 | _ -> Baz


If I uncomment the print statements in base.ml, I see this before the output:

ZZZ	let _ = Foo;;
XXX	Foo 0
ZZZ	let _ = Foo;;
ZZZ	let _ = Bar;;
XXX	Bar 0
ZZZ	let _ = Bar;;


So it seems my grammar extension only ever considers the inner-most expression
application. Perhaps further explanation is necessary. I examine the structure
of the expression application with the following experiment (call it exp.ml):

let p = <:str_item<
type t = Foo of int * int | Bar of int | Baz
    
let f = function
  | 1 -> Foo (1, 1)
  | 2 -> Bar 2
  | _ -> Baz
>>


I run the following command:

camlp4of exp.ml


It expands the quotation to a crazy big tree, the interesting bit being this:

		      (Ast.ExApp (_loc,
			 (Ast.ExApp (_loc,
			    (Ast.ExId (_loc, (Ast.IdUid (_loc, "Foo")))),
			    (Ast.ExInt (_loc, "1")))),
			 (Ast.ExInt (_loc, "1")))))),

It seems that my constructor of arity 2 can be located as an uppercase
identifier nested twice deep in ExApps. So either I do not understand how to
modify the grammar rule to catch this, or the problem is not in the rule?

Any help would be most appreciated. I've gotten this far by reading whatever
tutorials I could find and trying to follow along in the Camlp4 source code,
but I am now completely stumped. Thank you!

Eric Griffis
eagriffis@gmail.com

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [Caml-list] Camlp4 type constructor transformation
  2011-03-14 19:32 [Caml-list] Camlp4 type constructor transformation eagriffis
@ 2011-03-23  8:57 ` Hendrik Tews
  0 siblings, 0 replies; 2+ messages in thread
From: Hendrik Tews @ 2011-03-23  8:57 UTC (permalink / raw)
  To: caml-list

eagriffis@gmail.com writes:

   I am having trouble getting Camlp4 to detect and transform type constructors
   that take parameters. I believe the problem is with my grammar. Here is a base
   case (call it base.ml):

If you want to transform the syntax tree after parsing you should
not modify the grammar. Instead you should install a filter
function. Transforming the syntax tree is the very purpose of
filter functions.

If you look at the sources of the camlp4 parser, you see

    expr: LEVEL "apply" (* LEFTA *)
      [ [ e1 = SELF; e2 = SELF ->
            match (is_expr_constr_call e1, e2) with
            [ (True, <:expr< ( $tup:e$ ) >>) ->
                List.fold_left (fun e1 e2 -> <:expr< $e1$ $e2$ >>) e1
                                (Ast.list_of_expr e [])
            | _ -> <:expr< $e1$ $e2$ >> ]
      ] ];

i.e, your expression "Foo(1,1)" is first parsed as Foo applied to
a pair and only if is_expr_constr_call detects a constructor it
is transformed into Foo applied to 1 applied to 1.

Your rule

     expr: LEVEL "apply"
       [ LEFTA
   	[ e1 = SELF; e2 = SELF -> apply _loc e1 e2 ] ];

does not curry constructor calls. I don't understand the code in
Camlp4/Struct/Camlp4Ast2OCamlAst.ml, but I would expect that you
get strange errors if you connect this parser to the ocaml
compiler.

   It seems that my constructor of arity 2 can be located as an uppercase
   identifier nested twice deep in ExApps. So either I do not understand how to
   modify the grammar rule to catch this, or the problem is not in the rule?

This is true, but only after the transformation in the original
parser. Filter functions run after the parsing completed, so a
filter function sees precisely what you expect.


Bye,

Hendrik

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2011-03-23  8:57 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-03-14 19:32 [Caml-list] Camlp4 type constructor transformation eagriffis
2011-03-23  8:57 ` Hendrik Tews

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).