2013-04-18 08:06:33 -07:00
|
|
|
(* This filter implements the following extensions:
|
2012-06-29 02:36:32 -07:00
|
|
|
|
2013-04-18 08:06:33 -07:00
|
|
|
In structures:
|
2012-06-29 03:04:17 -07:00
|
|
|
|
2013-04-18 08:06:33 -07:00
|
|
|
[%%IFDEF X]
|
|
|
|
... --> included if the environment variable X is defined
|
|
|
|
[%%ELSE]
|
|
|
|
... --> included if the environment variable X is undefined
|
|
|
|
[%%END]
|
2012-06-29 03:04:17 -07:00
|
|
|
|
2013-04-18 08:06:33 -07:00
|
|
|
|
|
|
|
In expressions:
|
|
|
|
|
|
|
|
[%GETENV X] ---> the string literal representing the compile-time value
|
2012-06-29 03:04:17 -07:00
|
|
|
of environment variable X
|
2013-04-18 08:28:19 -07:00
|
|
|
|
|
|
|
|
|
|
|
In variant type declarations:
|
|
|
|
|
|
|
|
type t =
|
|
|
|
..
|
|
|
|
| C [@IFDEF X] of ... --> the constructor is kept only if X is defined
|
|
|
|
|
|
|
|
|
|
|
|
In match clauses (function/match...with/try...with):
|
|
|
|
|
|
|
|
|
|
|
|
P when [%IFDEF X] -> E --> the case is kept only if X is defined
|
|
|
|
|
2012-06-29 02:36:32 -07:00
|
|
|
*)
|
|
|
|
|
2013-04-18 08:06:33 -07:00
|
|
|
open Ast_helper
|
|
|
|
open Asttypes
|
2012-06-29 02:36:32 -07:00
|
|
|
open Parsetree
|
|
|
|
open Longident
|
|
|
|
open Location
|
|
|
|
|
2013-04-18 08:06:33 -07:00
|
|
|
let getenv arg =
|
|
|
|
match arg with
|
|
|
|
| {pexp_desc = Pexp_construct ({txt = Lident sym; _}, None); _} ->
|
|
|
|
(try Sys.getenv sym with Not_found -> "")
|
|
|
|
| {pexp_loc = loc; _} ->
|
|
|
|
Format.eprintf "%a** IFDEF: bad syntax."
|
|
|
|
Location.print_error loc;
|
|
|
|
exit 2
|
|
|
|
|
|
|
|
let empty_str_item = Str.include_ (Mod.structure [])
|
2012-06-29 03:04:17 -07:00
|
|
|
|
2012-06-29 02:36:32 -07:00
|
|
|
let ifdef =
|
2013-04-18 08:28:19 -07:00
|
|
|
object(this)
|
2013-04-18 08:06:33 -07:00
|
|
|
inherit Ast_mapper.mapper as super
|
|
|
|
|
|
|
|
val mutable stack = []
|
|
|
|
|
2013-04-18 08:28:19 -07:00
|
|
|
method eval_attributes =
|
|
|
|
List.for_all
|
|
|
|
(function
|
|
|
|
| "IFDEF", arg -> getenv arg <> ""
|
|
|
|
| "IFNDEF", arg -> getenv arg = ""
|
|
|
|
| _ -> true)
|
|
|
|
|
|
|
|
method filter_constr cd = this # eval_attributes cd.pcd_attributes
|
|
|
|
|
|
|
|
method! type_declaration = function
|
|
|
|
| {ptype_kind = Ptype_variant cstrs; _} as td ->
|
|
|
|
{td with ptype_kind =
|
|
|
|
Ptype_variant(List.filter (this # filter_constr) cstrs)}
|
|
|
|
| td -> td
|
|
|
|
|
|
|
|
method! cases l =
|
|
|
|
List.fold_right
|
|
|
|
(fun c rest ->
|
|
|
|
match c with
|
|
|
|
| {pc_guard=Some {pexp_desc=Pexp_extension("IFDEF", arg); _}; _} ->
|
|
|
|
if getenv arg = "" then rest else {c with pc_guard=None} :: rest
|
|
|
|
| c -> c :: rest
|
|
|
|
) l []
|
|
|
|
|
2013-04-18 08:06:33 -07:00
|
|
|
method! structure_item i =
|
|
|
|
match i.pstr_desc, stack with
|
|
|
|
| Pstr_extension(("IFDEF", arg), _), _ ->
|
|
|
|
stack <- (getenv arg <> "") :: stack;
|
|
|
|
empty_str_item
|
|
|
|
| Pstr_extension(("ELSE", _), _), (hd :: tl) ->
|
|
|
|
stack <- not hd :: tl;
|
|
|
|
empty_str_item
|
|
|
|
| Pstr_extension(("END", _), _), _ :: tl ->
|
|
|
|
stack <- tl;
|
|
|
|
empty_str_item
|
|
|
|
| Pstr_extension((("ELSE"|"END"), _), _), [] ->
|
|
|
|
Format.printf "%a** IFDEF: mo matching [%%%%IFDEF]"
|
|
|
|
Location.print_error i.pstr_loc;
|
2012-06-29 02:49:52 -07:00
|
|
|
exit 2
|
2013-04-18 08:06:33 -07:00
|
|
|
| _, (true :: _ | []) -> super # structure_item i
|
|
|
|
| _, false :: _ -> empty_str_item
|
2012-06-29 03:04:17 -07:00
|
|
|
|
|
|
|
method! expr = function
|
2013-04-18 08:06:33 -07:00
|
|
|
| {pexp_desc = Pexp_extension("GETENV", arg); pexp_loc = loc; _} ->
|
|
|
|
Exp.constant ~loc (Const_string (getenv arg, None))
|
2012-06-29 03:04:17 -07:00
|
|
|
| x -> super # expr x
|
2012-06-29 02:36:32 -07:00
|
|
|
end
|
|
|
|
|
2013-04-18 08:06:33 -07:00
|
|
|
let () = Ast_mapper.main ifdef
|