caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* 3.10.0+beta - "Not_found" from a custom camlp4 executable (Delete.delete_rule_in_suffix)
@ 2007-04-16 20:20 Aleksey Nogin
  2007-04-16 20:26 ` [Caml-list] " Nicolas Pouillard
  0 siblings, 1 reply; 5+ messages in thread
From: Aleksey Nogin @ 2007-04-16 20:20 UTC (permalink / raw)
  To: Caml List

I am trying to figure out how to use the new camlp4 (so that I can have 
some hope of migrating our MetaPRL Theorem Prover - http://metaprl.org/ 
to it). I thought that I'd start with something simple - port our local 
mods to pa_macro (now Camlp4MacroParser).

First, I tried making sure I know how to build and link the thing. 
Compiling an unmodified Camlp4MacroParser was not a problem, but then I 
got the following:

% ocamlc -g -thread -I -custom -o macroprint unix.cma threads.cma 
camlp4/camlp4lib.cma camlp4/Camlp4Printers/Camlp4OCamlPrinter.cmo 
camlp4/Camlp4Parsers/Camlp4OCamlParser.cmo Camlp4MacroParser.cmo 
camlp4/Camlp4Filters/Camlp4TrashRemover.cmo camlp4/Camlp4Bin.cmo -linkall

% ./macroprint
Camlp4: Uncaught exception: Not_found

ocamldebug revealed that the Not_found is being raised from the 
Delete.delete_rule_in_suffix function.

What am I doing wrong?

TIA for any help!

Aleksey


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

* Re: [Caml-list] 3.10.0+beta - "Not_found" from a custom camlp4 executable (Delete.delete_rule_in_suffix)
  2007-04-16 20:20 3.10.0+beta - "Not_found" from a custom camlp4 executable (Delete.delete_rule_in_suffix) Aleksey Nogin
@ 2007-04-16 20:26 ` Nicolas Pouillard
  2007-04-16 22:49   ` 3.10.0+beta: pa_macro vs Camlp4MacroParser [Was: "Not_found" from a custom camlp4 executable] Aleksey Nogin
  0 siblings, 1 reply; 5+ messages in thread
From: Nicolas Pouillard @ 2007-04-16 20:26 UTC (permalink / raw)
  To: Caml List, Aleksey Nogin

On 4/16/07, Aleksey Nogin <nogin@metaprl.org> wrote:
> I am trying to figure out how to use the new camlp4 (so that I can have
> some hope of migrating our MetaPRL Theorem Prover - http://metaprl.org/
> to it). I thought that I'd start with something simple - port our local
> mods to pa_macro (now Camlp4MacroParser).
>
> First, I tried making sure I know how to build and link the thing.
> Compiling an unmodified Camlp4MacroParser was not a problem, but then I
> got the following:
>
> % ocamlc -g -thread -I -custom -o macroprint unix.cma threads.cma
> camlp4/camlp4lib.cma camlp4/Camlp4Printers/Camlp4OCamlPrinter.cmo
> camlp4/Camlp4Parsers/Camlp4OCamlParser.cmo Camlp4MacroParser.cmo
> camlp4/Camlp4Filters/Camlp4TrashRemover.cmo camlp4/Camlp4Bin.cmo -linkall
>
> % ./macroprint
> Camlp4: Uncaught exception: Not_found
>
> ocamldebug revealed that the Not_found is being raised from the
> Delete.delete_rule_in_suffix function.
>
> What am I doing wrong?

That's a DELETE_RULE that cannot find the rule to remove, either it's
your DELETE_RULE or it's by loading some camlp4 code that does it.

> % ocamlc -g -thread -I -custom -o macroprint unix.cma threads.cma
> camlp4/camlp4lib.cma camlp4/Camlp4Printers/Camlp4OCamlPrinter.cmo
> camlp4/Camlp4Parsers/Camlp4OCamlParser.cmo Camlp4MacroParser.cmo
> camlp4/Camlp4Filters/Camlp4TrashRemover.cmo camlp4/Camlp4Bin.cmo -linkall

You should add the revised grammar before the original one since the
original is a syntax extension of the revised.

Regards,

-- 
Nicolas Pouillard


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

* 3.10.0+beta: pa_macro vs Camlp4MacroParser [Was: "Not_found" from a custom camlp4 executable]
  2007-04-16 20:26 ` [Caml-list] " Nicolas Pouillard
@ 2007-04-16 22:49   ` Aleksey Nogin
  2007-04-17  1:12     ` 3.10.0+beta: Corrected and improved Camlp4MacroParser Aleksey Nogin
  0 siblings, 1 reply; 5+ messages in thread
From: Aleksey Nogin @ 2007-04-16 22:49 UTC (permalink / raw)
  To: Caml List; +Cc: Nicolas Pouillard

On 16.04.2007 13:26, Nicolas Pouillard wrote:

>> % ocamlc -g -thread -I -custom -o macroprint unix.cma threads.cma
>> camlp4/camlp4lib.cma camlp4/Camlp4Printers/Camlp4OCamlPrinter.cmo
>> camlp4/Camlp4Parsers/Camlp4OCamlParser.cmo Camlp4MacroParser.cmo
>> camlp4/Camlp4Filters/Camlp4TrashRemover.cmo camlp4/Camlp4Bin.cmo -linkall
> 
> You should add the revised grammar before the original one since the
> original is a syntax extension of the revised.

Thanks a lot for your lightning-fast response! Yes, this is what I was 
missing - and once I've added the revisied syntax parser to the list of 
odules to compile, things started working (sort of).

Now that I can build it, I see that the "refactoring" of pa_macro into 
Camlp4MacroParser is, unfortunately, very broken in one important 
respect. In the pa_macro, the macro definitions inside an IFDEF were 
only collected while the body of IFDEF is parsed and were not executed 
until after the IFDEF is parsed and the condition is evaluated. In the 
"refactored" Camlp4MacroParser all the "DEFINE" directives are executed 
right away!

So, what this means is that

DEFINE TRUE;;
IFDEF TRUE THEN
   DEFINE XYZ = 1
ELSE
   DEFINE XYZ = 2
ENDIF;;
let xyz = XYZ;;

would correctly result in "let xyz = 1" in pa_macro, but with 
Camlp4MacroParser, I get "let xyz = 2"!

Also note that the item_or_def type that was responsible for collecting 
the "delayed" definitions in the pa_macro is no longer used in 
Camlp4MacroParser.

Aleksey


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

* 3.10.0+beta: Corrected and improved Camlp4MacroParser
  2007-04-16 22:49   ` 3.10.0+beta: pa_macro vs Camlp4MacroParser [Was: "Not_found" from a custom camlp4 executable] Aleksey Nogin
@ 2007-04-17  1:12     ` Aleksey Nogin
  2007-04-17 19:28       ` Nicolas Pouillard
  0 siblings, 1 reply; 5+ messages in thread
From: Aleksey Nogin @ 2007-04-17  1:12 UTC (permalink / raw)
  To: Nicolas Pouillard; +Cc: Caml List

[-- Attachment #1: Type: text/plain, Size: 1321 bytes --]

As I wrote to the list earlier, I have noticed that the 
Camlp4MacroParser in 3.10.0+beta has an unfortunate problem - when 
processing an "IFDEF" (or "IFNDEF") directive, it will execute the 
"DEFINE"s in _both_ branches, regardless of whether the test is true or 
not (this was caused by the fact that the DEFINE directives would be 
executed eagerly at parse-time).

Attached is a corrected and improved version of the Camlp4MacroParser:

- Fixes the above problem; now the execution of the "DEFINE" directives 
inside IFDEF/IFNDEF is correct.

- Adds support for "local" definitions
   DEFINE <lident> = <expression> IN <expression>
   This is particularly useful for things like

   DEFINE body =
     ...
   IN
   IFDEF DEBUG
     let result = body in
     print_debug result;
     result
   ELSE
     body

- Adds an ability to omit the "ELSE" part of the IFDEF/IFNDEF 
expressions (the "ELSE" branch is then taken to default to unit 
expression "()").

- Adds an ability to use the macro argument as a pattern (provided the 
argument is a sufficiently simple expression)

- Adds a special macro "NOTHING" that can be used to "wipe out" unneeded 
function arguments. This is useful to be able to generate functions of 
different arity using the same macro.

The improved Camlp4MacroParser.ml is attached.

Aleksey

[-- Attachment #2: Camlp4MacroParser.ml --]
[-- Type: text/plain, Size: 12376 bytes --]

open Camlp4;                                             (* -*- camlp4r -*- *)
(****************************************************************************)
(*                                                                          *)
(*                              Objective Caml                              *)
(*                                                                          *)
(*                            INRIA Rocquencourt                            *)
(*                                                                          *)
(*  Copyright  2006   Institut National de Recherche  en  Informatique et   *)
(*  en Automatique.  All rights reserved.  This file is distributed under   *)
(*  the terms of the GNU Library General Public License, with the special   *)
(*  exception on linking described in LICENSE at the top of the Objective   *)
(*  Caml source tree.                                                       *)
(*                                                                          *)
(****************************************************************************)

(* Authors:
 * - Daniel de Rauglaudre: initial version
 * - Nicolas Pouillard: refactoring
 * - Aleksey Nogin: extra features and bug fixes.
 *)

module Id = struct
  value name = "Camlp4MacroParser";
  value version = "$Id: Camlp4MacroParser.ml,v 1.1 2007/02/07 10:09:22 ertai Exp $";
end;

(*
Added statements:

  At toplevel (structure item):

     DEFINE <uident>
     DEFINE <uident> = <expression>
     DEFINE <uident> (<parameters>) = <expression>
     IFDEF <uident> THEN <structure_items> [ ELSE <structure_items> ] (END | ENDIF)
     IFNDEF <uident> THEN <structure_items> [ ELSE <structure_items> ] (END | ENDIF)
     INCLUDE <string>

  In expressions:

     IFDEF <uident> THEN <expression> [ ELSE <expression> ] (END | ENDIF)
     IFNDEF <uident> THEN <expression> [ ELSE <expression> ] (END | ENDIF)
     DEFINE <lident> = <expression> IN <expression>
     __FILE__
     __LOCATION__

  In patterns:

     IFDEF <uident> THEN <pattern> ELSE <pattern> (END | ENDIF)
     IFNDEF <uident> THEN <pattern> ELSE <pattern> (END | ENDIF)

  As Camlp4 options:

     -D<uident>                      define <uident>
     -U<uident>                      undefine it
     -I<dir>                         add <dir> to the search path for INCLUDE'd files

  After having used a DEFINE <uident> followed by "= <expression>", you
  can use it in expressions *and* in patterns. If the expression defining
  the macro cannot be used as a pattern, there is an error message if
  it is used in a pattern.

  You can also define a local macro in an expression usigng the DEFINE ... IN form.
  Note that local macros have lowercase names and can not take parameters.

  If a macro is defined to = NOTHING, and then used as an argument to a function,
  this will be equivalent to function taking one less argument. Similarly,
  passing NOTHING as an argument to a macro is equivalent to "erasing" the
  corresponding parameter from the macro body.

  The toplevel statement INCLUDE <string> can be used to include a
  file containing macro definitions and also any other toplevel items.
  The included files are looked up in directories passed in via the -I
  option, falling back to the current directory.

  The expression __FILE__ returns the current compiled file name.
  The expression __LOCATION__ returns the current location of itself.

*)

open Camlp4;

module Make (Syntax : Sig.Camlp4Syntax) = struct
  open Sig;
  include Syntax;

  type item_or_def 'a =
    [ SdStr of 'a
    | SdDef of string and option (list string * Ast.expr)
    | SdUnd of string
    | SdITE of string and list (item_or_def 'a) and list (item_or_def 'a)
    | SdInc of string ];

  value rec list_remove x =
    fun
    [ [(y, _) :: l] when y = x -> l
    | [d :: l] -> [d :: list_remove x l]
    | [] -> [] ];

  value defined = ref [];

  value is_defined i = List.mem_assoc i defined.val;

  value bad_patt _loc = 
    Loc.raise _loc
      (Failure
         "this macro cannot be used in a pattern (see its definition)");
  value substp _loc env =
    loop where rec loop =
      fun
      [ <:expr< $e1$ $e2$ >> -> <:patt< $loop e1$ $loop e2$ >>
      | <:expr< >> -> <:patt< >>
      | <:expr< $lid:x$ >> ->
          try List.assoc x env with
          [ Not_found -> <:patt< $lid:x$ >> ]
      | <:expr< $uid:x$ >> ->
          try List.assoc x env with
          [ Not_found -> <:patt< $uid:x$ >> ]
      | <:expr< $int:x$ >> -> <:patt< $int:x$ >>
      | <:expr< $str:s$ >> -> <:patt< $str:s$ >>
      | <:expr< ($tup:x$) >> -> <:patt< ($tup:loop x$) >>
      | <:expr< $x1$, $x2$ >> -> <:patt< $loop x1$, $loop x2$ >>
      | <:expr< { $bi$ } >> ->
          let rec substbi = fun
            [ <:binding< $b1$; $b2$ >> -> <:patt< $substbi b1$; $substbi b2$ >>
            | <:binding< $p$ = $e$ >> -> <:patt< $p$ = $loop e$ >>
            | _ -> bad_patt _loc ]
          in <:patt< { $substbi bi$ } >>
      | _ -> bad_patt _loc ];

  class reloc _loc = object
    inherit Ast.map as super;
    method _Loc_t _ = _loc;
  end;

  class subst _loc env = object
    inherit reloc _loc as super;
    method expr =
      fun
      [ <:expr< $lid:x$ >> | <:expr< $uid:x$ >> as e ->
          try List.assoc x env with
          [ Not_found -> super#expr e ]
      | e -> super#expr e ];

    method patt =
      fun
      [ <:patt< $lid:x$ >> | <:patt< $uid:x$ >> as p ->
         try substp _loc [] (List.assoc x env) with
         [ Not_found -> super#patt p ]
      | p -> super#patt p ];
  end;

  value incorrect_number loc l1 l2 =
    Loc.raise loc
      (Failure
        (Printf.sprintf "expected %d parameters; found %d"
            (List.length l2) (List.length l1)));

  value define eo x =
    do {
      match eo with
      [ Some ([], e) ->
          EXTEND Gram
            expr: LEVEL "simple"
              [ [ UIDENT $x$ -> (new reloc _loc)#expr e ]]
            ;
            patt: LEVEL "simple"
              [ [ UIDENT $x$ ->
                    let p = substp _loc [] e
                    in (new reloc _loc)#patt p ]]
            ;
          END
      | Some (sl, e) ->
          EXTEND Gram
            expr: LEVEL "apply"
              [ [ UIDENT $x$; param = SELF ->
                    let el =
                      match param with
                      [ <:expr< ($tup:e$) >> -> Ast.list_of_expr e []
                      | e -> [e] ]
                    in
                    if List.length el = List.length sl then
                      let env = List.combine sl el in
                      (new subst _loc env)#expr e
                    else
                      incorrect_number _loc el sl ] ]
            ;
            patt: LEVEL "simple"
              [ [ UIDENT $x$; param = SELF ->
                    let pl =
                      match param with
                      [ <:patt< ($tup:p$) >> -> Ast.list_of_patt p []
                      | p -> [p] ]
                    in
                    if List.length pl = List.length sl then
                      let env = List.combine sl pl in
                      let p = substp _loc env e in
                      (new reloc _loc)#patt p
                    else
                      incorrect_number _loc pl sl ] ]
            ;
          END
      | None -> () ];
      defined.val := [(x, eo) :: defined.val];
    };

  value undef x =
    try
      do {
        let eo = List.assoc x defined.val in
        match eo with
        [ Some ([], _) ->
            do {
              DELETE_RULE Gram expr: UIDENT $x$ END;
              DELETE_RULE Gram patt: UIDENT $x$ END;
            }
        | Some (_, _) ->
            do {
              DELETE_RULE Gram expr: UIDENT $x$; SELF END;
              DELETE_RULE Gram patt: UIDENT $x$; SELF END;
            }
        | None -> () ];
        defined.val := list_remove x defined.val;
      }
    with
    [ Not_found -> () ];

  (* This is a list of directories to search for INCLUDE statements. *)
  value include_dirs = ref [];

  (* Add something to the above, make sure it ends with a slash. *)
  value add_include_dir str =
    if str <> "" then
      let str =
        if String.get str ((String.length str)-1) = '/'
        then str else str ^ "/"
      in include_dirs.val := include_dirs.val @ [str]
    else ();

  value parse_include_file rule =
    let dir_ok file dir = Sys.file_exists (dir ^ file) in
    fun file ->
      let file =
        try (List.find (dir_ok file) (include_dirs.val @ ["./"])) ^ file
        with [ Not_found -> file ]
      in
      let ch = open_in file in
      let st = Stream.of_channel ch in
        Gram.parse rule (Loc.mk file) st;

  value nil_str_item =
    let _loc = Loc.ghost in <:str_item<>>;

  value rec execute_macro =
    fun
    [ SdStr i -> i
    | SdDef x eo -> do { define eo x; nil_str_item  }
    | SdUnd x -> do { undef x; nil_str_item }
    | SdITE i l1 l2 -> execute_macro_list (if is_defined i then l1 else l2)
    | SdInc f -> do { parse_include_file str_items f } ]

  and execute_macro_list = fun
  [ [] -> nil_str_item
  | [hd::tl] -> (* The evaluation order is important here *)
    let il1 = execute_macro hd in
    let il2 = execute_macro_list tl in
    let _loc = Loc.ghost in
      <:str_item< $list: [il1; il2]$ >> ] ;

  EXTEND Gram
    GLOBAL: expr patt str_item sig_item;
    str_item: FIRST
      [ [ x = macro_def -> execute_macro x ] ]
      ;
    macro_def:
      [ [ "DEFINE"; i = uident; def = opt_macro_value -> SdDef i def
        | "UNDEF"; i = uident -> SdUnd i
        | "IFDEF"; i = uident; "THEN"; st1 = smlist; st2 = else_macro_def ->
            SdITE i st1 st2
        | "IFNDEF"; i = uident; "THEN"; st2 = smlist; st1 = else_macro_def ->
            SdITE i st1 st2
        | "INCLUDE"; fname = STRING -> SdInc fname ] ]
    ;
    else_macro_def:
      [ [ "ELSE"; st = smlist; _ = endif -> st
        | _ = endif -> [] ] ]
    ;
    smlist:
      [ [ sml = LIST1 [ d = macro_def -> d | si = str_item -> SdStr si ] -> sml ] ]
    ;
    sig_item: FIRST
      [ [ "INCLUDE"; fname = STRING ->
            parse_include_file sig_items fname ] ]
    ;
    endif:
      [ [ "END" -> ()
        | "ENDIF" -> () ] ]
    ;
    opt_macro_value:
      [ [ "("; pl = LIST1 [ x = LIDENT -> x ] SEP ","; ")"; "="; e = expr -> Some (pl, e)
        | "="; e = expr -> Some ([], e)
        | -> None ] ]
    ;
    else_expr:
      [ [ "ELSE"; e = expr; _ = endif -> e
      | _ = endif -> <:expr< () >> ] ]
    ;
    expr: LEVEL "top"
      [ [ "IFDEF"; i = uident; "THEN"; e1 = expr; e2 = else_expr ->
            if is_defined i then e1 else e2
        | "IFNDEF"; i = uident; "THEN"; e1 = expr; e2 = else_expr ->
            if is_defined i then e2 else e1
        | "DEFINE"; i = LIDENT; "="; def = expr; "IN"; body = expr ->
            (new subst _loc [(i, def)])#expr body ] ]
    ;
    expr: LEVEL "simple"
      [ [ LIDENT "__FILE__" -> <:expr< $`str:Loc.file_name _loc$ >>
        | LIDENT "__LOCATION__" ->
            let (a, b, c, d, e, f, g, h) = Loc.to_tuple _loc in
            <:expr< Loc.of_tuple
                ($`str:a$, $`int:b$, $`int:c$, $`int:d$,
                 $`int:e$, $`int:f$, $`int:g$,
                 $if h then <:expr< True >> else <:expr< False >> $) >> ] ]
    ;
    patt:
      [ [ "IFDEF"; i = uident; "THEN"; p1 = patt; "ELSE"; p2 = patt; _ = endif ->
            if is_defined i then p1 else p2
        | "IFNDEF"; i = uident; "THEN"; p1 = patt; "ELSE"; p2 = patt; _ = endif ->
            if is_defined i then p2 else p1 ] ]
    ;
    uident:
      [ [ i = UIDENT -> i ] ]
    ;
  END;

  Options.add "-D" (Arg.String (define None))
    "<string> Define for IFDEF instruction.";
  Options.add "-U" (Arg.String undef)
    "<string> Undefine for IFDEF instruction.";
  Options.add "-I" (Arg.String add_include_dir)
    "<string> Add a directory to INCLUDE search path.";

end;

let module M = Register.OCamlSyntaxExtension Id Make in ();

module MakeNothing (AstFilters : Camlp4.Sig.AstFilters) = struct
  open AstFilters;
  open Ast;

  value rec map_expr =
    fun
    [ <:expr< $e$ NOTHING >>
    | <:expr< fun $ <:patt< NOTHING >> $ -> $e$ >>
      -> map_expr e
    | e -> e];

  register_str_item_filter (new Ast.c_expr map_expr)#str_item;

end;

let module M = Camlp4.Register.AstFilter Id MakeNothing in ();



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

* Re: 3.10.0+beta: Corrected and improved Camlp4MacroParser
  2007-04-17  1:12     ` 3.10.0+beta: Corrected and improved Camlp4MacroParser Aleksey Nogin
@ 2007-04-17 19:28       ` Nicolas Pouillard
  0 siblings, 0 replies; 5+ messages in thread
From: Nicolas Pouillard @ 2007-04-17 19:28 UTC (permalink / raw)
  To: Aleksey Nogin, Caml List

On 4/17/07, Aleksey Nogin <nogin@metaprl.org> wrote:
> As I wrote to the list earlier, I have noticed that the
> Camlp4MacroParser in 3.10.0+beta has an unfortunate problem - when
> processing an "IFDEF" (or "IFNDEF") directive, it will execute the
> "DEFINE"s in _both_ branches, regardless of whether the test is true or
> not (this was caused by the fact that the DEFINE directives would be
> executed eagerly at parse-time).
>
> Attached is a corrected and improved version of the Camlp4MacroParser:
>
> - Fixes the above problem; now the execution of the "DEFINE" directives
> inside IFDEF/IFNDEF is correct.
Ok

> - Adds support for "local" definitions
Cool, thanks.

I've merged your fix with the current status of Camlp4MacroParser
which now handles signature items and a more general -D<uident>=<expr>
option.

I've applied it to the CVS (release310 branch) that is now available
from the public CVS repository.

Since some changes have been applied to camlp4 since OCaml-3.10+beta
release I suggest you to get the last version to do your porting work.

Best regard and many thanks,

-- 
Nicolas Pouillard


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

end of thread, other threads:[~2007-04-17 19:28 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-04-16 20:20 3.10.0+beta - "Not_found" from a custom camlp4 executable (Delete.delete_rule_in_suffix) Aleksey Nogin
2007-04-16 20:26 ` [Caml-list] " Nicolas Pouillard
2007-04-16 22:49   ` 3.10.0+beta: pa_macro vs Camlp4MacroParser [Was: "Not_found" from a custom camlp4 executable] Aleksey Nogin
2007-04-17  1:12     ` 3.10.0+beta: Corrected and improved Camlp4MacroParser Aleksey Nogin
2007-04-17 19:28       ` Nicolas Pouillard

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