diff --git a/atd/src/annot.ml b/atd/src/annot.ml index bd94be71..4c4c9df0 100644 --- a/atd/src/annot.ml +++ b/atd/src/annot.ml @@ -214,3 +214,16 @@ let validate schema root = List.iter (fun sec -> validate_section sec root ) schema + +let filter_by_tags ~tags full_module = + let aux (annot : t) = + annot |> List.filter (fun (section, _) -> ( + match fields annot ~section ~field:"tag" with + | [] -> true + | fields -> + fields + |> List.filter_map snd + |> List.exists (fun value -> List.mem value tags) + )) + in + Ast.map_all_annot aux full_module diff --git a/atd/src/annot.mli b/atd/src/annot.mli index 690a7b7a..01f685ce 100644 --- a/atd/src/annot.mli +++ b/atd/src/annot.mli @@ -203,3 +203,10 @@ type schema = schema_section list (** Check that annotations of interest are not misplaced. Raises an exception with an error message when the check fails. *) val validate : schema -> Ast.any -> unit + +(** + Remove annotations which do not have at least one of the provided [tags] found in their tag field. +*) +val filter_by_tags : + tags : string list -> + Ast.full_module -> Ast.full_module diff --git a/atd/src/json.ml b/atd/src/json.ml index 37abb3aa..a11e778f 100644 --- a/atd/src/json.ml +++ b/atd/src/json.ml @@ -90,6 +90,12 @@ let annot_schema_json : Annot.schema = [ Variant, "name"; Field, "name"; Field, "tag_field"; + Module_head, "tag"; + Type_def, "tag"; + Type_expr, "tag"; + Variant, "tag"; + Cell, "tag"; + Field, "tag"; ] }; { diff --git a/atd/src/util.ml b/atd/src/util.ml index cd186d12..9adbad44 100644 --- a/atd/src/util.ml +++ b/atd/src/util.ml @@ -8,6 +8,7 @@ let read_lexbuf ?(inherit_variants = false) ?(pos_fname = "") ?(pos_lnum = 1) + ~tags lexbuf = Lexer.init_fname lexbuf pos_fname pos_lnum; @@ -30,12 +31,16 @@ let read_lexbuf | Some schema -> Annot.validate schema (Ast.Full_module full_module) ); + let full_module = match tags with + | [] -> full_module + | tags -> Annot.filter_by_tags ~tags full_module + in (full_module, original_types) let read_channel ?annot_schema ?expand ?keep_builtins ?keep_poly ?xdebug ?inherit_fields ?inherit_variants - ?pos_fname ?pos_lnum + ?pos_fname ?pos_lnum ~tags ic = let lexbuf = Lexing.from_channel ic in let pos_fname = @@ -45,12 +50,12 @@ let read_channel pos_fname in read_lexbuf ?annot_schema ?expand ?keep_builtins ?keep_poly ?xdebug - ?inherit_fields ?inherit_variants ?pos_fname ?pos_lnum lexbuf + ?inherit_fields ?inherit_variants ?pos_fname ?pos_lnum ~tags lexbuf let load_file ?annot_schema ?expand ?keep_builtins ?keep_poly ?xdebug ?inherit_fields ?inherit_variants - ?pos_fname ?pos_lnum + ?pos_fname ?pos_lnum ~tags file = let ic = open_in file in let finally () = close_in_noerr ic in @@ -63,7 +68,7 @@ let load_file let ast = read_channel ?annot_schema ?expand ?keep_builtins ?keep_poly ?xdebug - ?inherit_fields ?inherit_variants ?pos_fname ?pos_lnum ic + ?inherit_fields ?inherit_variants ?pos_fname ?pos_lnum ~tags ic in finally (); ast @@ -74,11 +79,11 @@ let load_file let load_string ?annot_schema ?expand ?keep_builtins ?keep_poly ?xdebug ?inherit_fields ?inherit_variants - ?pos_fname ?pos_lnum + ?pos_fname ?pos_lnum ~tags s = let lexbuf = Lexing.from_string s in read_lexbuf ?annot_schema ?expand ?keep_builtins ?keep_poly ?xdebug - ?inherit_fields ?inherit_variants ?pos_fname ?pos_lnum lexbuf + ?inherit_fields ?inherit_variants ?pos_fname ?pos_lnum ~tags lexbuf module Tsort = Sort.Make ( struct diff --git a/atd/src/util.mli b/atd/src/util.mli index aeb0e258..0d5d92fb 100644 --- a/atd/src/util.mli +++ b/atd/src/util.mli @@ -10,6 +10,7 @@ val read_lexbuf : ?inherit_variants:bool -> ?pos_fname:string -> ?pos_lnum:int -> + tags:string list -> Lexing.lexbuf -> Ast.full_module * Expand.original_types (** Read an ATD file from a lexbuf. See also [read_channel], [load_file] and [load_string]. @@ -66,6 +67,7 @@ val read_channel : ?inherit_variants:bool -> ?pos_fname:string -> ?pos_lnum:int -> + tags:string list -> in_channel -> Ast.full_module * Expand.original_types (** Read an ATD file from an [in_channel]. Options: see [read_lexbuf]. The default [pos_fname] is set to [""] when appropriate. *) @@ -80,6 +82,7 @@ val load_file : ?inherit_variants:bool -> ?pos_fname:string -> ?pos_lnum:int -> + tags:string list -> string -> Ast.full_module * Expand.original_types (** Read an ATD file. Options: see [read_lexbuf]. The default [pos_fname] is the given input file name. *) @@ -94,6 +97,7 @@ val load_string : ?inherit_variants:bool -> ?pos_fname:string -> ?pos_lnum:int -> + tags:string list -> string -> Ast.full_module * Expand.original_types (** Read ATD data from a string. Options: see [read_lexbuf]. *) diff --git a/atd/test/annot.ml b/atd/test/annot.ml index d830ba3e..3cd816c9 100644 --- a/atd/test/annot.ml +++ b/atd/test/annot.ml @@ -31,11 +31,11 @@ let schema : Atd.Annot.schema = [ ] let test_valid_input atd_input = - let root, _orig_types = Atd.Util.load_string atd_input in + let root, _orig_types = Atd.Util.load_string ~tags:[] atd_input in Atd.Annot.validate schema (Atd.Ast.Full_module root) let test_invalid_input atd_input = - let root, _orig_types = Atd.Util.load_string atd_input in + let root, _orig_types = Atd.Util.load_string ~tags:[] atd_input in try Atd.Annot.validate schema (Atd.Ast.Full_module root); assert false diff --git a/atdcat/src/atdcat.ml b/atdcat/src/atdcat.ml index 228478cb..2b02655c 100644 --- a/atdcat/src/atdcat.ml +++ b/atdcat/src/atdcat.ml @@ -78,7 +78,7 @@ let parse fun file -> let m, _orig_defs = Atd.Util.load_file ~annot_schema ~expand ~keep_poly ~xdebug - ~inherit_fields ~inherit_variants file + ~inherit_fields ~inherit_variants ~tags:[] file in if remove_wraps then Atd.Ast.remove_wrap_constructs m diff --git a/atdcpp/src/bin/Atdcpp_main.ml b/atdcpp/src/bin/Atdcpp_main.ml index 2457fb32..15dfdcdd 100644 --- a/atdcpp/src/bin/Atdcpp_main.ml +++ b/atdcpp/src/bin/Atdcpp_main.ml @@ -7,6 +7,7 @@ open Cmdliner type conf = { input_files: string list; + tags: string list; version: bool; } @@ -18,7 +19,7 @@ let run conf = else conf.input_files |> List.iter (fun atd_file -> - Atdcpp.Codegen.run_file atd_file + Atdcpp.Codegen.run_file ~tags:conf.tags atd_file ) (***************************************************************************) @@ -38,6 +39,13 @@ let input_files_term = let default = [] in Arg.value (Arg.pos_all Arg.file default info) +let tags_term = + let info = + Arg.info ["tag"] + ~doc:"Only evaluate annotations which have either the provided TAG as a field value <... tag=TAG>, or have no tags specified.\nOption can be used multiple times to specify several tags" + in + Arg.value (Arg.opt_all Arg.string [] info) + let version_term = let info = Arg.info ["version"] @@ -94,14 +102,16 @@ type bar = [ ] let cmdline_term run = - let combine input_files version = + let combine input_files tags version = run { input_files; version; + tags; } in Term.(const combine $ input_files_term + $ tags_term $ version_term ) diff --git a/atdcpp/src/lib/Codegen.ml b/atdcpp/src/lib/Codegen.ml index 874460eb..31b864d2 100644 --- a/atdcpp/src/lib/Codegen.ml +++ b/atdcpp/src/lib/Codegen.ml @@ -34,6 +34,12 @@ let annot_schema_cpp : Atd.Annot.schema_section = Field, "default"; Module_head, "include"; Module_head, "namespace"; + Module_head, "tag"; + Type_def, "tag"; + Type_expr, "tag"; + Variant, "tag"; + Cell, "tag"; + Field, "tag"; ] } @@ -1576,7 +1582,7 @@ let to_cpp_file ~atd_filename (items : A.module_body) dst_path namespace_name = |> double_spaced |> Indent.to_file ~indent:4 dst_path -let run_file src_path = +let run_file ~tags src_path = let src_name = Filename.basename src_path in let dst_name = (if Filename.check_suffix src_name ".atd" then @@ -1594,6 +1600,7 @@ let run_file src_path = ~keep_builtins:true ~inherit_fields:true ~inherit_variants:true + ~tags src_path in let full_module = Atd.Ast.use_only_specific_variants full_module in diff --git a/atdcpp/src/lib/Codegen.mli b/atdcpp/src/lib/Codegen.mli index fc58e255..c0e4286e 100644 --- a/atdcpp/src/lib/Codegen.mli +++ b/atdcpp/src/lib/Codegen.mli @@ -4,4 +4,4 @@ (** Take ATD type definitions and translate them to C++, writing them out to a file which should have the '.d' extension. *) -val run_file : string -> unit +val run_file : tags:string list -> string -> unit diff --git a/atdd/src/bin/Atdd_main.ml b/atdd/src/bin/Atdd_main.ml index da4576e2..efcfae9c 100644 --- a/atdd/src/bin/Atdd_main.ml +++ b/atdd/src/bin/Atdd_main.ml @@ -7,6 +7,7 @@ open Cmdliner type conf = { input_files: string list; + tags: string list; version: bool; } @@ -18,7 +19,7 @@ let run conf = else conf.input_files |> List.iter (fun atd_file -> - Atdd.Codegen.run_file atd_file + Atdd.Codegen.run_file ~tags:conf.tags atd_file ) (***************************************************************************) @@ -38,6 +39,13 @@ let input_files_term = let default = [] in Arg.value (Arg.pos_all Arg.file default info) +let tags_term = + let info = + Arg.info ["tag"] + ~doc:"Only evaluate annotations which have either the provided TAG as a field value <... tag=TAG>, or have no tags specified.\nOption can be used multiple times to specify several tags" + in + Arg.value (Arg.opt_all Arg.string [] info) + let version_term = let info = Arg.info ["version"] @@ -94,14 +102,16 @@ type bar = [ ] let cmdline_term run = - let combine input_files version = + let combine input_files tags version = run { input_files; version; + tags; } in Term.(const combine $ input_files_term + $ tags_term $ version_term ) diff --git a/atdd/src/lib/Codegen.ml b/atdd/src/lib/Codegen.ml index 491d8b61..9e65ff26 100644 --- a/atdd/src/lib/Codegen.ml +++ b/atdd/src/lib/Codegen.ml @@ -32,6 +32,12 @@ let annot_schema_dlang : Atd.Annot.schema_section = Type_expr, "wrap"; Field, "default"; Module_head, "import"; + Module_head, "tag"; + Type_def, "tag"; + Type_expr, "tag"; + Variant, "tag"; + Cell, "tag"; + Field, "tag"; ] } @@ -1126,7 +1132,7 @@ let to_file ~atd_filename ~head (items : A.module_body) dst_path = |> double_spaced |> Indent.to_file ~indent:4 dst_path -let run_file src_path = +let run_file ~tags src_path = let src_name = Filename.basename src_path in let dst_name = (if Filename.check_suffix src_name ".atd" then @@ -1143,6 +1149,7 @@ let run_file src_path = ~keep_builtins:true ~inherit_fields:true ~inherit_variants:true + ~tags src_path in let full_module = Atd.Ast.use_only_specific_variants full_module in diff --git a/atdd/src/lib/Codegen.mli b/atdd/src/lib/Codegen.mli index 180fb5ef..67e93fdd 100644 --- a/atdd/src/lib/Codegen.mli +++ b/atdd/src/lib/Codegen.mli @@ -4,4 +4,4 @@ (** Take ATD type definitions and translate them to Dlang, writing them out to a file which should have the '.d' extension. *) -val run_file : string -> unit +val run_file : tags:string list -> string -> unit diff --git a/atddiff/src/lib/Atddiff.ml b/atddiff/src/lib/Atddiff.ml index 97eb4113..7e8db203 100644 --- a/atddiff/src/lib/Atddiff.ml +++ b/atddiff/src/lib/Atddiff.ml @@ -52,6 +52,7 @@ let compare_files |> Atd.Util.load_file ~inherit_fields:true (* simplifies comparison *) ~inherit_variants:true (* simplifies comparison *) + ~tags:[] |> fst |> Atd.Ast.remove_wrap_constructs in diff --git a/atdgen/bin/ag_main.ml b/atdgen/bin/ag_main.ml index 906025ed..755df866 100644 --- a/atdgen/bin/ag_main.ml +++ b/atdgen/bin/ag_main.ml @@ -71,6 +71,10 @@ let main () = let l = Re.Str.split (Re.Str.regexp " *, *\\| +") s in opens := List.rev_append l !opens in + let tags = ref [] in + let add_tags t = + tags := List.rev_append t !tags + in let pp_convs : Ocaml.pp_convs ref = ref (Ocaml.Ppx_deriving []) in let set_pp_convs arg = match !pp_convs with @@ -104,6 +108,14 @@ let main () = Insert '[@@ATTR]' after OCaml type definitions. Option can be used multiple times to specify several attributes "; + "-tag", Arg.String (fun s -> add_tags [ s ]), + " + TAG + Only evaluate annotations which have either + - the provided TAG as a field value <... tag=TAG>, + - or have no tags specified. + Option can be used multiple times to specify several tags + "; "-t", Arg.Unit (fun () -> set_once "output type" mode T; set_once "no function definitions" with_fundefs false), @@ -422,6 +434,7 @@ Recommended usage: %s (-t|-b|-j|-v|-dep|-list|-mel) example.atd" Sys.argv.(0) in ~type_aliases ~force_defaults ~ocaml_version + ~tags:!tags atd_file ocaml_prefix let () = diff --git a/atdgen/src/biniou.ml b/atdgen/src/biniou.ml index ce554c24..565b3146 100644 --- a/atdgen/src/biniou.ml +++ b/atdgen/src/biniou.ml @@ -41,6 +41,12 @@ let annot_schema_biniou : Atd.Annot.schema = [ section = "biniou"; fields = [ Type_expr, "repr"; + Module_head, "tag"; + Type_def, "tag"; + Type_expr, "tag"; + Variant, "tag"; + Cell, "tag"; + Field, "tag"; ] }; { @@ -50,6 +56,12 @@ let annot_schema_biniou : Atd.Annot.schema = [ Type_def, "module"; Type_def, "predef"; Type_def, "t"; + Module_head, "tag"; + Type_def, "tag"; + Type_expr, "tag"; + Variant, "tag"; + Cell, "tag"; + Field, "tag"; ] }; ] diff --git a/atdgen/src/ob_emit.ml b/atdgen/src/ob_emit.ml index ed68b823..66f5373c 100644 --- a/atdgen/src/ob_emit.ml +++ b/atdgen/src/ob_emit.ml @@ -1357,6 +1357,7 @@ let make_ocaml_files ~force_defaults:_ ~ocaml_version ~pp_convs + ~tags atd_file out = let ((head, m0), _) = match atd_file with @@ -1364,13 +1365,13 @@ let make_ocaml_files Atd.Util.load_file ~annot_schema ~expand:false ~inherit_fields:true ~inherit_variants:true - ?pos_fname ?pos_lnum + ?pos_fname ?pos_lnum ~tags file | None -> Atd.Util.read_channel ~annot_schema ~expand:false ~inherit_fields:true ~inherit_variants:true - ?pos_fname ?pos_lnum + ?pos_fname ?pos_lnum ~tags stdin in let tsort = diff --git a/atdgen/src/ob_emit.mli b/atdgen/src/ob_emit.mli index eabcd213..3ccce659 100644 --- a/atdgen/src/ob_emit.mli +++ b/atdgen/src/ob_emit.mli @@ -12,4 +12,5 @@ val make_ocaml_files -> force_defaults:_ (* not used *) -> ocaml_version:(int * int) option -> pp_convs:Ocaml.pp_convs + -> tags:string list -> string option -> Ox_emit.target -> unit diff --git a/atdgen/src/ocaml.ml b/atdgen/src/ocaml.ml index 94aa285d..fdf6ee21 100644 --- a/atdgen/src/ocaml.ml +++ b/atdgen/src/ocaml.ml @@ -169,6 +169,12 @@ let annot_schema_ocaml : Atd.Annot.schema_section = Field, "mutable"; Field, "name"; Field, "repr"; + Module_head, "tag"; + Type_def, "tag"; + Type_expr, "tag"; + Variant, "tag"; + Cell, "tag"; + Field, "tag"; ] } diff --git a/atdgen/src/oj_emit.ml b/atdgen/src/oj_emit.ml index e182afb9..60fd9ebb 100644 --- a/atdgen/src/oj_emit.ml +++ b/atdgen/src/oj_emit.ml @@ -1338,6 +1338,7 @@ let make_ocaml_files ~preprocess_input ~ocaml_version ~pp_convs + ~tags atd_file out = let ((head, m0), _) = match atd_file with @@ -1345,13 +1346,13 @@ let make_ocaml_files Atd.Util.load_file ~annot_schema ~expand:false ~inherit_fields:true ~inherit_variants:true - ?pos_fname ?pos_lnum + ?pos_fname ?pos_lnum ~tags file | None -> Atd.Util.read_channel ~annot_schema ~expand:false ~inherit_fields:true ~inherit_variants:true - ?pos_fname ?pos_lnum + ?pos_fname ?pos_lnum ~tags stdin in diff --git a/atdgen/src/oj_emit.mli b/atdgen/src/oj_emit.mli index 29384958..e21ee25d 100644 --- a/atdgen/src/oj_emit.mli +++ b/atdgen/src/oj_emit.mli @@ -15,6 +15,7 @@ val make_ocaml_files -> preprocess_input:string option -> ocaml_version:(int * int) option -> pp_convs:Ocaml.pp_convs + -> tags:string list -> string option -> Ox_emit.target -> unit diff --git a/atdgen/src/omelange_emit.ml b/atdgen/src/omelange_emit.ml index f9a29b8e..bbe6a0e5 100644 --- a/atdgen/src/omelange_emit.ml +++ b/atdgen/src/omelange_emit.ml @@ -713,6 +713,7 @@ let make_ocaml_files ~force_defaults:_ ~ocaml_version ~pp_convs:_ + ~tags atd_file out = let ((head, m0), _) = match atd_file with @@ -720,13 +721,13 @@ let make_ocaml_files Atd.Util.load_file ~annot_schema ~expand:false ~inherit_fields:true ~inherit_variants:true - ?pos_fname ?pos_lnum + ?pos_fname ?pos_lnum ~tags file | None -> Atd.Util.read_channel ~annot_schema ~expand:false ~inherit_fields:true ~inherit_variants:true - ?pos_fname ?pos_lnum + ?pos_fname ?pos_lnum ~tags stdin in diff --git a/atdgen/src/omelange_emit.mli b/atdgen/src/omelange_emit.mli index a234305d..f225dccf 100644 --- a/atdgen/src/omelange_emit.mli +++ b/atdgen/src/omelange_emit.mli @@ -11,6 +11,7 @@ val make_ocaml_files -> force_defaults:'a -> ocaml_version:'b -> pp_convs:'c + -> tags:string list -> string option -> Ox_emit.target -> unit diff --git a/atdgen/src/ov_emit.ml b/atdgen/src/ov_emit.ml index 68374e74..6731705b 100644 --- a/atdgen/src/ov_emit.ml +++ b/atdgen/src/ov_emit.ml @@ -423,6 +423,7 @@ let make_ocaml_files ~force_defaults:_ ~ocaml_version:_ ~pp_convs + ~tags atd_file out = let ((head, m0), _) = match atd_file with @@ -430,13 +431,13 @@ let make_ocaml_files Atd.Util.load_file ~annot_schema ~expand:false ~inherit_fields:true ~inherit_variants:true - ?pos_fname ?pos_lnum + ?pos_fname ?pos_lnum ~tags file | None -> Atd.Util.read_channel ~annot_schema ~expand:false ~inherit_fields:true ~inherit_variants:true - ?pos_fname ?pos_lnum + ?pos_fname ?pos_lnum ~tags stdin in let tsort = diff --git a/atdgen/src/ov_emit.mli b/atdgen/src/ov_emit.mli index afc0295d..b438ec41 100644 --- a/atdgen/src/ov_emit.mli +++ b/atdgen/src/ov_emit.mli @@ -12,4 +12,5 @@ val make_ocaml_files -> force_defaults:_ (* TODO unused *) -> ocaml_version:_ (* TODO unused *) -> pp_convs:Ocaml.pp_convs + -> tags:string list -> string option -> Ox_emit.target -> unit diff --git a/atdgen/test/dune b/atdgen/test/dune index 87417b0c..cccb6901 100644 --- a/atdgen/test/dune +++ b/atdgen/test/dune @@ -258,6 +258,21 @@ (package atdgen) (action (diff test_annot_error.expected.stdout test_annot_error.stdout))) +(rule + (targets test_annot_tags_j.ml test_annot_tags_j.mli) + (deps test_annot_tags.atd) + (action (run %{bin:atdgen} -tag=melange -j -j-std %{deps}))) + +(rule + (alias runtest) + (package atdgen) + (action (diff test_annot_tags_j.expected.ml test_annot_tags_j.ml))) + +(rule + (alias runtest) + (package atdgen) + (action (diff test_annot_tags_j.expected.mli test_annot_tags_j.mli))) + ;; inline records are not allowed within poly variant, but allowed in classic (rule diff --git a/atdgen/test/test_annot_tags.atd b/atdgen/test/test_annot_tags.atd new file mode 100644 index 00000000..39ffc66f --- /dev/null +++ b/atdgen/test/test_annot_tags.atd @@ -0,0 +1,6 @@ +type t = { + id : int; + always_array : string list ; + melange_array : string list ; + ml_array : string list ; +} \ No newline at end of file diff --git a/atdgen/test/test_annot_tags_j.expected.ml b/atdgen/test/test_annot_tags_j.expected.ml new file mode 100644 index 00000000..ae1ad422 --- /dev/null +++ b/atdgen/test/test_annot_tags_j.expected.ml @@ -0,0 +1,297 @@ +(* Auto-generated from "test_annot_tags.atd" *) +[@@@ocaml.warning "-27-32-33-35-39"] + +type t = Test_annot_tags_t.t = { + id: int; + always_array: string Atdgen_runtime.Util.ocaml_array; + melange_array: string Atdgen_runtime.Util.ocaml_array; + ml_array: string list +} + +let write__x_f5dfc61 = ( + Atdgen_runtime.Oj_run.write_array ( + Yojson.Safe.write_string + ) +) +let string_of__x_f5dfc61 ?(len = 1024) x = + let ob = Buffer.create len in + write__x_f5dfc61 ob x; + Buffer.contents ob +let read__x_f5dfc61 = ( + Atdgen_runtime.Oj_run.read_array ( + Atdgen_runtime.Oj_run.read_string + ) +) +let _x_f5dfc61_of_string s = + read__x_f5dfc61 (Yojson.Safe.init_lexer ()) (Lexing.from_string s) +let write__x_20d39e2 = ( + Atdgen_runtime.Oj_run.write_array ( + Yojson.Safe.write_string + ) +) +let string_of__x_20d39e2 ?(len = 1024) x = + let ob = Buffer.create len in + write__x_20d39e2 ob x; + Buffer.contents ob +let read__x_20d39e2 = ( + Atdgen_runtime.Oj_run.read_array ( + Atdgen_runtime.Oj_run.read_string + ) +) +let _x_20d39e2_of_string s = + read__x_20d39e2 (Yojson.Safe.init_lexer ()) (Lexing.from_string s) +let write__string_list = ( + Atdgen_runtime.Oj_run.write_list ( + Yojson.Safe.write_string + ) +) +let string_of__string_list ?(len = 1024) x = + let ob = Buffer.create len in + write__string_list ob x; + Buffer.contents ob +let read__string_list = ( + Atdgen_runtime.Oj_run.read_list ( + Atdgen_runtime.Oj_run.read_string + ) +) +let _string_list_of_string s = + read__string_list (Yojson.Safe.init_lexer ()) (Lexing.from_string s) +let write_t : _ -> t -> _ = ( + fun ob (x : t) -> + Buffer.add_char ob '{'; + let is_first = ref true in + if !is_first then + is_first := false + else + Buffer.add_char ob ','; + Buffer.add_string ob "\"id\":"; + ( + Yojson.Safe.write_int + ) + ob x.id; + if !is_first then + is_first := false + else + Buffer.add_char ob ','; + Buffer.add_string ob "\"always_array\":"; + ( + write__x_20d39e2 + ) + ob x.always_array; + if !is_first then + is_first := false + else + Buffer.add_char ob ','; + Buffer.add_string ob "\"melange_array\":"; + ( + write__x_f5dfc61 + ) + ob x.melange_array; + if !is_first then + is_first := false + else + Buffer.add_char ob ','; + Buffer.add_string ob "\"ml_array\":"; + ( + write__string_list + ) + ob x.ml_array; + Buffer.add_char ob '}'; +) +let string_of_t ?(len = 1024) x = + let ob = Buffer.create len in + write_t ob x; + Buffer.contents ob +let read_t = ( + fun p lb -> + Yojson.Safe.read_space p lb; + Yojson.Safe.read_lcurl p lb; + let field_id = ref (None) in + let field_always_array = ref (None) in + let field_melange_array = ref (None) in + let field_ml_array = ref (None) in + try + Yojson.Safe.read_space p lb; + Yojson.Safe.read_object_end lb; + Yojson.Safe.read_space p lb; + let f = + fun s pos len -> + if pos < 0 || len < 0 || pos + len > String.length s then + invalid_arg (Printf.sprintf "out-of-bounds substring position or length: string = %S, requested position = %i, requested length = %i" s pos len); + match len with + | 2 -> ( + if String.unsafe_get s pos = 'i' && String.unsafe_get s (pos+1) = 'd' then ( + 0 + ) + else ( + -1 + ) + ) + | 8 -> ( + if String.unsafe_get s pos = 'm' && String.unsafe_get s (pos+1) = 'l' && String.unsafe_get s (pos+2) = '_' && String.unsafe_get s (pos+3) = 'a' && String.unsafe_get s (pos+4) = 'r' && String.unsafe_get s (pos+5) = 'r' && String.unsafe_get s (pos+6) = 'a' && String.unsafe_get s (pos+7) = 'y' then ( + 3 + ) + else ( + -1 + ) + ) + | 12 -> ( + if String.unsafe_get s pos = 'a' && String.unsafe_get s (pos+1) = 'l' && String.unsafe_get s (pos+2) = 'w' && String.unsafe_get s (pos+3) = 'a' && String.unsafe_get s (pos+4) = 'y' && String.unsafe_get s (pos+5) = 's' && String.unsafe_get s (pos+6) = '_' && String.unsafe_get s (pos+7) = 'a' && String.unsafe_get s (pos+8) = 'r' && String.unsafe_get s (pos+9) = 'r' && String.unsafe_get s (pos+10) = 'a' && String.unsafe_get s (pos+11) = 'y' then ( + 1 + ) + else ( + -1 + ) + ) + | 13 -> ( + if String.unsafe_get s pos = 'm' && String.unsafe_get s (pos+1) = 'e' && String.unsafe_get s (pos+2) = 'l' && String.unsafe_get s (pos+3) = 'a' && String.unsafe_get s (pos+4) = 'n' && String.unsafe_get s (pos+5) = 'g' && String.unsafe_get s (pos+6) = 'e' && String.unsafe_get s (pos+7) = '_' && String.unsafe_get s (pos+8) = 'a' && String.unsafe_get s (pos+9) = 'r' && String.unsafe_get s (pos+10) = 'r' && String.unsafe_get s (pos+11) = 'a' && String.unsafe_get s (pos+12) = 'y' then ( + 2 + ) + else ( + -1 + ) + ) + | _ -> ( + -1 + ) + in + let i = Yojson.Safe.map_ident p f lb in + Atdgen_runtime.Oj_run.read_until_field_value p lb; + ( + match i with + | 0 -> + field_id := ( + Some ( + ( + Atdgen_runtime.Oj_run.read_int + ) p lb + ) + ); + | 1 -> + field_always_array := ( + Some ( + ( + read__x_20d39e2 + ) p lb + ) + ); + | 2 -> + field_melange_array := ( + Some ( + ( + read__x_f5dfc61 + ) p lb + ) + ); + | 3 -> + field_ml_array := ( + Some ( + ( + read__string_list + ) p lb + ) + ); + | _ -> ( + Yojson.Safe.skip_json p lb + ) + ); + while true do + Yojson.Safe.read_space p lb; + Yojson.Safe.read_object_sep p lb; + Yojson.Safe.read_space p lb; + let f = + fun s pos len -> + if pos < 0 || len < 0 || pos + len > String.length s then + invalid_arg (Printf.sprintf "out-of-bounds substring position or length: string = %S, requested position = %i, requested length = %i" s pos len); + match len with + | 2 -> ( + if String.unsafe_get s pos = 'i' && String.unsafe_get s (pos+1) = 'd' then ( + 0 + ) + else ( + -1 + ) + ) + | 8 -> ( + if String.unsafe_get s pos = 'm' && String.unsafe_get s (pos+1) = 'l' && String.unsafe_get s (pos+2) = '_' && String.unsafe_get s (pos+3) = 'a' && String.unsafe_get s (pos+4) = 'r' && String.unsafe_get s (pos+5) = 'r' && String.unsafe_get s (pos+6) = 'a' && String.unsafe_get s (pos+7) = 'y' then ( + 3 + ) + else ( + -1 + ) + ) + | 12 -> ( + if String.unsafe_get s pos = 'a' && String.unsafe_get s (pos+1) = 'l' && String.unsafe_get s (pos+2) = 'w' && String.unsafe_get s (pos+3) = 'a' && String.unsafe_get s (pos+4) = 'y' && String.unsafe_get s (pos+5) = 's' && String.unsafe_get s (pos+6) = '_' && String.unsafe_get s (pos+7) = 'a' && String.unsafe_get s (pos+8) = 'r' && String.unsafe_get s (pos+9) = 'r' && String.unsafe_get s (pos+10) = 'a' && String.unsafe_get s (pos+11) = 'y' then ( + 1 + ) + else ( + -1 + ) + ) + | 13 -> ( + if String.unsafe_get s pos = 'm' && String.unsafe_get s (pos+1) = 'e' && String.unsafe_get s (pos+2) = 'l' && String.unsafe_get s (pos+3) = 'a' && String.unsafe_get s (pos+4) = 'n' && String.unsafe_get s (pos+5) = 'g' && String.unsafe_get s (pos+6) = 'e' && String.unsafe_get s (pos+7) = '_' && String.unsafe_get s (pos+8) = 'a' && String.unsafe_get s (pos+9) = 'r' && String.unsafe_get s (pos+10) = 'r' && String.unsafe_get s (pos+11) = 'a' && String.unsafe_get s (pos+12) = 'y' then ( + 2 + ) + else ( + -1 + ) + ) + | _ -> ( + -1 + ) + in + let i = Yojson.Safe.map_ident p f lb in + Atdgen_runtime.Oj_run.read_until_field_value p lb; + ( + match i with + | 0 -> + field_id := ( + Some ( + ( + Atdgen_runtime.Oj_run.read_int + ) p lb + ) + ); + | 1 -> + field_always_array := ( + Some ( + ( + read__x_20d39e2 + ) p lb + ) + ); + | 2 -> + field_melange_array := ( + Some ( + ( + read__x_f5dfc61 + ) p lb + ) + ); + | 3 -> + field_ml_array := ( + Some ( + ( + read__string_list + ) p lb + ) + ); + | _ -> ( + Yojson.Safe.skip_json p lb + ) + ); + done; + assert false; + with Yojson.End_of_object -> ( + ( + { + id = (match !field_id with Some x -> x | None -> Atdgen_runtime.Oj_run.missing_field p "id"); + always_array = (match !field_always_array with Some x -> x | None -> Atdgen_runtime.Oj_run.missing_field p "always_array"); + melange_array = (match !field_melange_array with Some x -> x | None -> Atdgen_runtime.Oj_run.missing_field p "melange_array"); + ml_array = (match !field_ml_array with Some x -> x | None -> Atdgen_runtime.Oj_run.missing_field p "ml_array"); + } + : t) + ) +) +let t_of_string s = + read_t (Yojson.Safe.init_lexer ()) (Lexing.from_string s) diff --git a/atdgen/test/test_annot_tags_j.expected.mli b/atdgen/test/test_annot_tags_j.expected.mli new file mode 100644 index 00000000..6383e822 --- /dev/null +++ b/atdgen/test/test_annot_tags_j.expected.mli @@ -0,0 +1,30 @@ +(* Auto-generated from "test_annot_tags.atd" *) +[@@@ocaml.warning "-27-32-33-35-39"] + +type t = Test_annot_tags_t.t = { + id: int; + always_array: string Atdgen_runtime.Util.ocaml_array; + melange_array: string Atdgen_runtime.Util.ocaml_array; + ml_array: string list +} + +val write_t : + Buffer.t -> t -> unit + (** Output a JSON value of type {!type:t}. *) + +val string_of_t : + ?len:int -> t -> string + (** Serialize a value of type {!type:t} + into a JSON string. + @param len specifies the initial length + of the buffer used internally. + Default: 1024. *) + +val read_t : + Yojson.Safe.lexer_state -> Lexing.lexbuf -> t + (** Input JSON data of type {!type:t}. *) + +val t_of_string : + string -> t + (** Deserialize JSON data of type {!type:t}. *) + diff --git a/atdj/src/atdj_env.ml b/atdj/src/atdj_env.ml index 4f72c78b..14fadd54 100644 --- a/atdj/src/atdj_env.ml +++ b/atdj/src/atdj_env.ml @@ -13,6 +13,7 @@ type ty = type env_t = { module_items : (string * Atd.Ast.type_expr) list; + tags : string list; package : string; package_dir : string; input_file : string option; @@ -20,6 +21,7 @@ type env_t = { let default_env = { module_items = []; + tags = []; package = "out"; package_dir = "out"; input_file = None; diff --git a/atdj/src/atdj_main.ml b/atdj/src/atdj_main.ml index 3b5a4923..81507391 100644 --- a/atdj/src/atdj_main.ml +++ b/atdj/src/atdj_main.ml @@ -6,7 +6,14 @@ open Atdj_env let args_spec env = Arg.align [ "-package", Arg.String (fun x -> env := { !env with package = x }), - " Package name of generated files" + " Package name of generated files"; + + "-tag", + Arg.String (fun x -> env := { !env with tags = (x :: !env.tags) }), + " Only evaluate annotations which have either \n + - the provided TAG as a field value <... tag=TAG>, \n + - or have no tags specified. \n + Option can be used multiple times to specify several tags" ] let usage_msg = "Usage: " ^ Sys.argv.(0) ^ " \nOptions are:" @@ -64,7 +71,7 @@ let main () = (* Parse ATD file *) let (atd_head, atd_module), _original_types = Atd.Util.load_file - ~expand:false ~inherit_fields:true ~inherit_variants:true input_file + ~expand:false ~inherit_fields:true ~inherit_variants:true ~tags:env.tags input_file in let env = { env with diff --git a/atdj/src/dune b/atdj/src/dune index 78e671c9..07d944ea 100644 --- a/atdj/src/dune +++ b/atdj/src/dune @@ -2,4 +2,4 @@ (name atdj_main) (public_name atdj) (package atdj) - (libraries re atd)) + (libraries unix re atd)) diff --git a/atdpy/src/bin/Atdpy_main.ml b/atdpy/src/bin/Atdpy_main.ml index bfcf7317..ad917e80 100644 --- a/atdpy/src/bin/Atdpy_main.ml +++ b/atdpy/src/bin/Atdpy_main.ml @@ -7,6 +7,7 @@ open Cmdliner type conf = { input_files: string list; + tags: string list; version: bool; } @@ -18,7 +19,7 @@ let run conf = else conf.input_files |> List.iter (fun atd_file -> - Atdpy.Codegen.run_file atd_file + Atdpy.Codegen.run_file ~tags:conf.tags atd_file ) (***************************************************************************) @@ -38,6 +39,13 @@ let input_files_term = let default = [] in Arg.value (Arg.pos_all Arg.file default info) +let tags_term = + let info = + Arg.info ["tag"] + ~doc:"Only evaluate annotations which have either the provided TAG as a field value <... tag=TAG>, or have no tags specified.\nOption can be used multiple times to specify several tags" + in + Arg.value (Arg.opt_all Arg.string [] info) + let version_term = let info = Arg.info ["version"] @@ -94,14 +102,16 @@ type bar = [ ] let cmdline_term run = - let combine input_files version = + let combine input_files tags version = run { input_files; + tags; version; } in Term.(const combine $ input_files_term + $ tags_term $ version_term ) diff --git a/atdpy/src/lib/Codegen.ml b/atdpy/src/lib/Codegen.ml index 2e3e7eec..7fc86097 100644 --- a/atdpy/src/lib/Codegen.ml +++ b/atdpy/src/lib/Codegen.ml @@ -46,6 +46,12 @@ let annot_schema_python : Atd.Annot.schema_section = Type_def, "decorator"; Type_expr, "repr"; Field, "default"; + Module_head, "tag"; + Type_def, "tag"; + Type_expr, "tag"; + Variant, "tag"; + Cell, "tag"; + Field, "tag"; ] } @@ -1230,7 +1236,7 @@ let to_file ~atd_filename ~head (items : A.module_body) dst_path = |> double_spaced |> Indent.to_file ~indent:4 dst_path -let run_file src_path = +let run_file ~tags src_path = let src_name = Filename.basename src_path in let dst_name = (if Filename.check_suffix src_name ".atd" then @@ -1247,6 +1253,7 @@ let run_file src_path = ~keep_builtins:true ~inherit_fields:true ~inherit_variants:true + ~tags src_path in let full_module = Atd.Ast.use_only_specific_variants full_module in diff --git a/atdpy/src/lib/Codegen.mli b/atdpy/src/lib/Codegen.mli index 941192d1..f6cef54d 100644 --- a/atdpy/src/lib/Codegen.mli +++ b/atdpy/src/lib/Codegen.mli @@ -4,4 +4,4 @@ (** Take ATD type definitions and translate them to Python, writing them out to a file which should have the '.py' extension. *) -val run_file : string -> unit +val run_file : tags:string list -> string -> unit diff --git a/atds/src/atds_env.ml b/atds/src/atds_env.ml index 1d7fdb3c..7226b9fb 100644 --- a/atds/src/atds_env.ml +++ b/atds/src/atds_env.ml @@ -5,6 +5,7 @@ type ty_name = string type env_t = { module_items : (string * Atd.Ast.type_expr) list; + tags : string list; package : string; input_file : string option; output : out_channel; @@ -12,6 +13,7 @@ type env_t = { let default_env = { module_items = []; + tags = []; package = "out"; input_file = None; output = stdout; diff --git a/atds/src/atds_main.ml b/atds/src/atds_main.ml index 3fdfc867..5eab1cc5 100644 --- a/atds/src/atds_main.ml +++ b/atds/src/atds_main.ml @@ -9,7 +9,13 @@ let args_spec env = Arg.align " Package name of generated files"; "-o", Arg.String (fun x -> env := { !env with output = open_out x }), - " File name for Scala output" + " File name for Scala output"; + "-tag", + Arg.String (fun x -> env := { !env with tags = (x :: !env.tags) }), + " Only evaluate annotations which have either \n + - the provided TAG as a field value <... tag=TAG>, \n + - or have no tags specified. \n + Option can be used multiple times to specify several tags" ] let usage_msg = "Usage: " ^ Sys.argv.(0) ^ " \nOptions are:" @@ -49,7 +55,7 @@ let main () = (* Parse ATD file *) let (atd_head, atd_module), _original_types = Atd.Util.load_file - ~expand:false ~inherit_fields:true ~inherit_variants:true input_file + ~expand:false ~inherit_fields:true ~inherit_variants:true ~tags:env.tags input_file in let env = { env with diff --git a/atdts/src/bin/Atdts_main.ml b/atdts/src/bin/Atdts_main.ml index dd38d126..865a063b 100644 --- a/atdts/src/bin/Atdts_main.ml +++ b/atdts/src/bin/Atdts_main.ml @@ -7,6 +7,7 @@ open Cmdliner type conf = { input_files: string list; + tags: string list; version: bool; } @@ -18,7 +19,7 @@ let run conf = else conf.input_files |> List.iter (fun atd_file -> - Atdts.Codegen.run_file atd_file + Atdts.Codegen.run_file ~tags:conf.tags atd_file ) (***************************************************************************) @@ -38,6 +39,13 @@ let input_files_term = let default = [] in Arg.value (Arg.pos_all Arg.file default info) +let tags_term = + let info = + Arg.info ["tag"] + ~doc:"Only evaluate annotations which have either the provided TAG as a field value <... tag=TAG>, or have no tags specified.\nOption can be used multiple times to specify several tags" + in + Arg.value (Arg.opt_all Arg.string [] info) + let version_term = let info = Arg.info ["version"] @@ -92,14 +100,16 @@ type bar = [ ] let cmdline_term run = - let combine input_files version = + let combine input_files tags version = run { input_files; + tags; version; } in Term.(const combine $ input_files_term + $ tags_term $ version_term ) diff --git a/atdts/src/lib/Codegen.ml b/atdts/src/lib/Codegen.ml index 5473f4f0..850c6abd 100644 --- a/atdts/src/lib/Codegen.ml +++ b/atdts/src/lib/Codegen.ml @@ -25,6 +25,12 @@ let annot_schema_ts : Atd.Annot.schema_section = fields = [ Type_expr, "repr"; Field, "default"; + Module_head, "tag"; + Type_def, "tag"; + Type_expr, "tag"; + Variant, "tag"; + Cell, "tag"; + Field, "tag"; ] } @@ -1161,7 +1167,7 @@ let to_file ~atd_filename (items : A.module_body) dst_path = |> spaced |> Indent.to_file ~indent:2 dst_path -let run_file src_path = +let run_file ~tags src_path = let src_name = Filename.basename src_path in let dst_name = (if Filename.check_suffix src_name ".atd" then @@ -1178,6 +1184,7 @@ let run_file src_path = ~keep_builtins:true ~inherit_fields:true ~inherit_variants:true + ~tags src_path in let full_module = diff --git a/atdts/src/lib/Codegen.mli b/atdts/src/lib/Codegen.mli index e72afe06..f3a71574 100644 --- a/atdts/src/lib/Codegen.mli +++ b/atdts/src/lib/Codegen.mli @@ -4,4 +4,4 @@ (** Take ATD type definitions and translate them to TypeScript, writing them out to a file which should have the '.ts' extension. *) -val run_file : string -> unit +val run_file : tags:string list -> string -> unit