| Attached Files | Camlp4MacroParser.ml [^] (12,376 bytes) 2007-04-17 19:23
report4262_Camlp4MacroParser_patch.txt [^] (7,600 bytes) 2007-04-17 19:26 [Show Content] [Hide Content]--- Camlp4MacroParser.ml.orig 2007-02-07 02:09:22.000000000 -0800
+++ Camlp4MacroParser.ml 2007-04-16 18:09:11.728997000 -0700
@@ -16,6 +16,7 @@
(* Authors:
* - Daniel de Rauglaudre: initial version
* - Nicolas Pouillard: refactoring
+ * - Aleksey Nogin: extra features and bug fixes.
*)
module Id = struct
@@ -31,16 +32,15 @@
DEFINE <uident>
DEFINE <uident> = <expression>
DEFINE <uident> (<parameters>) = <expression>
- IFDEF <uident> THEN <structure_items> (END | ENDIF)
- IFDEF <uident> THEN <structure_items> ELSE <structure_items> (END | ENDIF)
- IFNDEF <uident> THEN <structure_items> (END | ENDIF)
- IFNDEF <uident> THEN <structure_items> ELSE <structure_items> (END | ENDIF)
+ 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)
+ IFDEF <uident> THEN <expression> [ ELSE <expression> ] (END | ENDIF)
+ IFNDEF <uident> THEN <expression> [ ELSE <expression> ] (END | ENDIF)
+ DEFINE <lident> = <expression> IN <expression>
__FILE__
__LOCATION__
@@ -60,7 +60,13 @@
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.
@@ -82,7 +88,7 @@
[ SdStr of 'a
| SdDef of string and option (list string * Ast.expr)
| SdUnd of string
- | SdITE of string and 'a and 'a
+ | SdITE of string and list (item_or_def 'a) and list (item_or_def 'a)
| SdInc of string ];
value rec list_remove x =
@@ -95,21 +101,6 @@
value is_defined i = List.mem_assoc i defined.val;
- 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 -> e ]
- | e -> super#expr e ];
- end;
-
value bad_patt _loc =
Loc.raise _loc
(Failure
@@ -118,6 +109,7 @@
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$ >> ]
@@ -136,6 +128,28 @@
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
@@ -234,23 +248,45 @@
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
- [ [ "DEFINE"; i = uident; def = opt_macro_value ->
- do { define def i; <:str_item<>> }
- | "UNDEF"; i = uident ->
- do { undef i; <:str_item<>> }
- | "IFDEF"; i = uident; "THEN"; st = str_items; _ = endif ->
- if is_defined i then st else <:str_item<>>
- | "IFDEF"; i = uident; "THEN"; st1 = str_items; "ELSE"; st2 = str_items; _ = endif ->
- if is_defined i then st1 else st2
- | "IFNDEF"; i = uident; "THEN"; st = str_items; _ = endif ->
- if is_defined i then <:str_item<>> else st
- | "IFNDEF"; i = uident; "THEN"; st1 = str_items; "ELSE"; st2 = str_items; _ = endif ->
- if is_defined i then st2 else st1
- | "INCLUDE"; fname = STRING ->
- parse_include_file str_items fname ] ]
+ [ [ 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 ->
@@ -265,11 +301,17 @@
| "="; e = expr -> Some ([], e)
| -> None ] ]
;
+ else_expr:
+ [ [ "ELSE"; e = expr; _ = endif -> e
+ | _ = endif -> <:expr< () >> ] ]
+ ;
expr: LEVEL "top"
- [ [ "IFDEF"; i = uident; "THEN"; e1 = expr; "ELSE"; e2 = expr; _ = endif ->
+ [ [ "IFDEF"; i = uident; "THEN"; e1 = expr; e2 = else_expr ->
if is_defined i then e1 else e2
- | "IFNDEF"; i = uident; "THEN"; e1 = expr; "ELSE"; e2 = expr; _ = endif ->
- if is_defined i then e2 else e1 ] ]
+ | "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$ >>
@@ -301,3 +343,22 @@
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 ();
+
+
|