caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Daniel de Rauglaudre <daniel.de_rauglaudre@inria.fr>
To: caml-list@inria.fr
Subject: Re: [Caml-list] Again on pattern matching and strings
Date: Fri, 25 Oct 2002 12:29:59 +0200	[thread overview]
Message-ID: <20021025122959.C21492@verdot.inria.fr> (raw)
In-Reply-To: <15799.62120.815873.654039@hector.lesours>; from basile@starynkevitch.net on Thu, Oct 24, 2002 at 03:16:24PM +0200

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

Hi,

Here attached, a proposition of Camlp4 standard syntax extension for
macros. The file is named "pa_macro.ml". To compile it do:
      ocamlc -pp camlp4r -I +camlp4 -c pa_macro.ml

To use it for a file "foo.ml", do:
   To compile:
       ocamlc -pp "camlp4o ./pa_macro.cmo" foo.ml
   To just pretty print the resulting source:
       camlp4o ./pa_macro.cmo pr_o.cmo foo.ml

The added statements are indicated in the beginning of the file
pa_macro.ml.

Keywords uppercase or lowercase?

I choosed to write the keywords in uppercase because I consider that
they must be visible in the source, just like the "#define" and other
"#ifdef" of C are visible, because of the "#" and because of the fact
that they are in the first column.

And I have considered also that in an expression, it is important
to differentiate "ifs" as conditional compilation and normal "ifs".

On Thu, Oct 24, 2002 at 03:16:24PM +0200, Basile STARYNKEVITCH wrote:

>    #ifdef WANT_DEBUG
>    #define DEBUGME(V) if (debugflag) printf("%d", V)
>    #else
>    #define DEBUGME(V) {}
>    #endif

With pa_macro.cmo, you can write it like this:

   IFDEF WANT_DEBUG THEN
     DEFINE DEBUGME(v) = if (debugflag) then printf("%d", v)
   ELSE
     DEFINE DEBUGME(v) = ()
   END

To define "WANT_DEBUG" you can either insert in the source:
   DEFINE DEBUGME

Or add "-DWANT_DEBUG" as option:
   camlp4o ./pa_macros.cmo pr_o.cmo -DWANT_DEBUG foo.ml
   ocamlc -pp "camlp4o ./pa_macros.cmo -DWANT_DEBUG" foo.ml

> 5. having the equivalent of __FILE__ and __LINE__ is very useful

Ok file __FILE__.
For __LINE__, it is complicated. I added __LOCATION__.

Any comments?

-- 
Daniel de RAUGLAUDRE
http://cristal.inria.fr/~ddr/

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

(* camlp4r *)
(* $Id$ *)

(*
Added statements:

  At toplevel (structure item):

     DEFINE <uident>
     DEFINE <uident> = <expression>
     DEFINE <uident> (<parameters>) = <expression>
     IFDEF <uident> THEN <structure_items> END
     IFDEF <uident> THEN <structure_items> ELSE <structure_items> END
     IFNDEF <uident> THEN <structure_items> END
     IFNDEF <uident> THEN <structure_items> ELSE <structure_items> END

  In expressions:

     IFDEF <uident> THEN <expression> ELSE <expression> END
     IFNDEF <uident> THEN <expression> ELSE <expression> END
     __FILE__
     __LOCATION__

  As Camlp4 options:

     -D<uident>
     -U<uident>

  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.

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

*)

#load "pa_extend.cmo";
#load "q_MLast.cmo";

open Pcaml;

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

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

value defined =
  ref [("OCAML_305", None); ("CAMLP4_300", None); ("NEWSEQ", None)]
;

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

value loc = (0, 0);

value subst mloc env =
  loop where rec loop =
    fun
    [ <:expr< if $e1$ then $e2$ else $e3$ >> ->
         <:expr< if $loop e1$ then $loop e2$ else $loop e3$ >>
    | <:expr< $e1$ $e2$ >> -> <:expr< $loop e1$ $loop e2$ >>
    | <:expr< $lid:x$ >> | <:expr< $uid:x$ >> as e ->
        try <:expr< $anti:List.assoc x env$ >> with
        [ Not_found -> e ]
    | <:expr< ($list:x$) >> -> <:expr< ($list:List.map loop x$) >>
    | <:expr< { $list:pel$ } >> ->
        let pel = List.map (fun (p, e) -> (p, loop e)) pel in
        <:expr< { $list:pel$ } >>
    | e -> e ]
;

value substp mloc env =
  loop where rec loop =
    fun
    [ <:expr< $e1$ $e2$ >> -> <:patt< $loop e1$ $loop e2$ >>
    | <:expr< $lid:x$ >> ->
        try <:patt< $anti:List.assoc x env$ >> with
        [ Not_found -> <:patt< $lid:x$ >> ]
    | <:expr< $uid:x$ >> ->
        try <:patt< $anti:List.assoc x env$ >> with
        [ Not_found -> <:patt< $uid:x$ >> ]
    | <:expr< $int:x$ >> -> <:patt< $int:x$ >>
    | <:expr< ($list:x$) >> -> <:patt< ($list:List.map loop x$) >>
    | <:expr< { $list:pel$ } >> ->
        let ppl = List.map (fun (p, e) -> (p, loop e)) pel in
        <:patt< { $list:ppl$ } >>
    | x ->
        Stdpp.raise_with_loc mloc
          (Failure
             "this macro cannot be used in a pattern (see its definition)") ]
;

value incorrect_number loc l1 l2 =
  Stdpp.raise_with_loc 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
          expr: LEVEL "simple"
            [ [ UIDENT $x$ -> Pcaml.expr_reloc (fun _ -> loc) 0 e ] ]
          ;
          patt: LEVEL "simple"
            [ [ UIDENT $x$ ->
                  let p = substp loc [] e in
                  Pcaml.patt_reloc (fun _ -> loc) 0 p ] ]
          ;
        END
    | Some (sl, e) ->
        EXTEND
          expr: LEVEL "apply"
            [ [ UIDENT $x$; param = SELF ->
                  let el =
                    match param with
                    [ <:expr< ($list:el$) >> -> el
                    | e -> [e] ]
                  in
                  if List.length el = List.length sl then
                    let env = List.combine sl el in
                    let e = subst loc env e in
                    Pcaml.expr_reloc (fun _ -> loc) 0 e
                  else
                    incorrect_number loc el sl ] ]
          ;
          patt: LEVEL "simple"
            [ [ UIDENT $x$; param = SELF ->
                  let pl =
                    match param with
                    [ <:patt< ($list:pl$) >> -> pl
                    | 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
                    Pcaml.patt_reloc (fun _ -> loc) 0 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 expr: UIDENT $x$ END;
            DELETE_RULE patt: UIDENT $x$ END;
          }
      | Some (_, _) ->
          do {
            DELETE_RULE expr: UIDENT $x$; SELF END;
            DELETE_RULE patt: UIDENT $x$; SELF END;
          }
      | None -> () ];
      defined.val := list_remove x defined.val;
    }
  with
  [ Not_found -> () ]
;

EXTEND
  GLOBAL: expr str_item sig_item;
  str_item: FIRST
    [ [ x = macro_def ->
          match x with
          [ SdStr [si] -> si
          | SdStr sil -> <:str_item< declare $list:sil$ end >>
          | SdDef x eo -> do { define eo x; <:str_item< declare end >> }
          | SdUnd x -> do { undef x; <:str_item< declare end >> }
          | SdNop -> <:str_item< declare end >> ] ] ]
  ;
  macro_def:
    [ [ "DEFINE"; i = ident; def = opt_macro_value -> SdDef i def
      | "UNDEF"; i = ident -> SdUnd i
      | "IFDEF"; i = ident; "THEN"; d = str_item_or_macro; "END" ->
          if is_defined i then d else SdNop
      | "IFDEF"; i = ident; "THEN"; d1 = str_item_or_macro; "ELSE";
        d2 = str_item_or_macro; "END" ->
          if is_defined i then d1 else d2
      | "IFNDEF"; i = ident; "THEN"; d = str_item_or_macro; "END" ->
          if is_defined i then SdNop else d
      | "IFNDEF"; i = ident; "THEN"; d1 = str_item_or_macro; "ELSE";
        d2 = str_item_or_macro; "END" ->
          if is_defined i then d2 else d1 ] ]
  ;
  str_item_or_macro:
    [ [ d = macro_def -> d
      | si = LIST1 str_item -> SdStr si ] ]
  ;
  opt_macro_value:
    [ [ "("; pl = LIST1 LIDENT SEP ","; ")"; "="; e = expr -> Some (pl, e)
      | "="; e = expr -> Some ([], e)
      | -> None ] ]
  ;
  expr: LEVEL "top"
    [ [ "IFDEF"; i = ident; "THEN"; e1 = expr; "ELSE"; e2 = expr; "END" ->
          if is_defined i then e1 else e2
      | "IFNDEF"; i = ident; "THEN"; e1 = expr; "ELSE"; e2 = expr; "END" ->
          if is_defined i then e2 else e1 ] ]
  ;
  expr: LEVEL "simple"
    [ [ LIDENT "__FILE__" -> <:expr< $str:Pcaml.input_file.val$ >>
      | LIDENT "__LOCATION__" ->
          let bp = string_of_int (fst loc) in
          let ep = string_of_int (snd loc) in
          <:expr< ($int:bp$, $int:ep$) >> ] ]
  ;
  ident:
    [ [ i = UIDENT -> i ] ]
  ;
END;

Pcaml.add_option "-D" (Arg.String (define None))
  "<string> Define for IFDEF instruction."
;
Pcaml.add_option "-U" (Arg.String undef)
  "<string> Undefine for IFDEF instruction."
;

  reply	other threads:[~2002-10-25 10:30 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-10-23 23:47 Alessandro Baretta
2002-10-23 23:46 ` Alexander V.Voinov
2002-10-23 23:57 ` Stefano Zacchiroli
2002-10-24  7:10   ` Alessandro Baretta
2002-10-24  7:38     ` Stefano Zacchiroli
2002-10-24  8:01     ` Jacques Garrigue
2002-10-24 12:38       ` Alessandro Baretta
2002-10-24 13:24         ` Luc Maranget
2002-10-24 15:13           ` Alessandro Baretta
2002-10-24 16:26           ` Sven Luther
2002-10-25  8:40             ` Luc Maranget
2002-10-24  4:11 ` Christopher Quinn
     [not found] ` <15799.14325.887770.501722@karryall.dnsalias.org>
2002-10-24  7:43   ` Alessandro Baretta
2002-10-24  8:51     ` Daniel de Rauglaudre
2002-10-24  9:50       ` Stefano Zacchiroli
2002-10-24 10:30         ` Noel Welsh
2002-10-24 12:59         ` Daniel de Rauglaudre
2002-10-24 13:16           ` Basile STARYNKEVITCH
2002-10-25 10:29             ` Daniel de Rauglaudre [this message]
2002-10-24 12:34       ` Alessandro Baretta
2002-10-24 12:51         ` Daniel de Rauglaudre
     [not found] <IIEMJEMIMDMLIIPHPOBLOELNCAAA.fsmith@mathworks.com>
2002-10-24  7:16 ` Alessandro Baretta

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=20021025122959.C21492@verdot.inria.fr \
    --to=daniel.de_rauglaudre@inria.fr \
    --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).