2 * Copyright (c) Facebook, Inc. and its affiliates.
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the "hack" directory of this source tree.
10 open Direct_decl_parser
14 ~enable_xhp_class_modifier
15 ~disable_xhp_element_mangling
16 ~enable_enum_classes
=
17 let po = ParserOptions.default
in
19 ParserOptions.with_disable_xhp_element_mangling
21 disable_xhp_element_mangling
23 let po = ParserOptions.with_auto_namespace_map
po auto_namespace_map
in
25 ParserOptions.with_enable_xhp_class_modifier
po enable_xhp_class_modifier
27 let po = ParserOptions.with_enable_enum_classes
po enable_enum_classes
in
30 let init root
popt : Provider_context.t
=
31 Relative_path.(set_path_prefix Root root
);
32 let (_handle
: SharedMem.handle
) =
33 SharedMem.init ~num_workers
:0 SharedMem.default_config
38 GlobalOptions.tco_shallow_class_decl
= true;
39 tco_higher_kinded_types
= true;
42 (* TODO(hverr): Figure out 64-bit *)
44 Provider_context.empty_for_tool
47 ~backend
:Provider_backend.Shared_memory
48 ~deps_mode
:Typing_deps_mode.SQLiteMode
51 (* Push local stacks here so we don't include shared memory in our timing. *)
52 File_provider.local_changes_push_sharedmem_stack
();
53 Decl_provider.local_changes_push_sharedmem_stack
();
54 Shallow_classes_provider.local_changes_push_sharedmem_stack
();
55 Linearization_provider.local_changes_push_sharedmem_stack
();
59 let rec shallow_declare_ast ctx decls prog
=
60 List.fold prog ~
init:decls ~f
:(fun decls def
->
63 | Namespace
(_
, prog
) -> shallow_declare_ast ctx decls prog
64 | NamespaceUse _
-> decls
65 | SetNamespaceEnv _
-> decls
66 | FileAttributes _
-> decls
68 let (name
, decl
) = Decl_nast.fun_naming_and_decl
ctx f
in
69 (name
, Shallow_decl_defs.Fun decl
) :: decls
71 let decl = Shallow_classes_provider.decl ctx c
in
72 let (_
, name
) = decl.Shallow_decl_defs.sc_name
in
73 (name
, Shallow_decl_defs.Class
decl) :: decls
75 let (name
, decl) = Decl_nast.record_def_naming_and_decl
ctx rd
in
76 (name
, Shallow_decl_defs.Record
decl) :: decls
78 let (name
, decl) = Decl_nast.typedef_naming_and_decl
ctx typedef
in
79 (name
, Shallow_decl_defs.Typedef
decl) :: decls
82 let (name
, ty
) = Decl_nast.const_naming_and_decl
ctx cst
in
83 let decl = Typing_defs.{ cd_pos
= fst cst
.cst_name
; cd_type
= ty
} in
84 (name
, Shallow_decl_defs.Const
decl) :: decls
)
86 let compare_decls ctx fn text
=
89 add_or_overwrite_entry_contents ~
ctx ~path
:fn ~contents
:text
)
91 let ast = Ast_provider.get_ast
ctx fn
in
92 let legacy_decls = shallow_declare_ast ctx [] ast in
93 let legacy_decls_str = show_decls
(List.rev
legacy_decls) ^
"\n" in
94 let popt = Provider_context.get_popt
ctx in
95 let auto_namespace_map = ParserOptions.auto_namespace_map popt in
96 let disable_xhp_element_mangling =
97 ParserOptions.disable_xhp_element_mangling popt
100 parse_decls_ffi
disable_xhp_element_mangling fn text
auto_namespace_map
102 let decls_str = show_decls
(List.rev
decls) ^
"\n" in
103 let matched = String.equal
decls_str legacy_decls_str in
105 Printf.eprintf
"%s%!" decls_str
107 Tempfile.with_real_tempdir
(fun dir
->
108 let temp_dir = Path.to_string dir
in
110 Caml.Filename.temp_file ~
temp_dir "expected_decls" ".txt"
112 let actual = Caml.Filename.temp_file ~
temp_dir "actual_decls" ".txt" in
113 Disk.write_file ~file
:expected ~contents
:legacy_decls_str;
114 Disk.write_file ~file
:actual ~contents
:decls_str;
115 Ppxlib_print_diff.print
116 ~diff_command
:"diff -U9999 --label legacy --label 'direct decl'"
122 type modes
= CompareDirectDeclParser
126 Printf.sprintf
"Usage: %s [OPTIONS] mode filename\n" Sys.argv
.(0)
128 let usage_and_exit () =
132 let mode = ref None
in
135 | None
-> mode := Some m
136 | Some _
-> usage_and_exit ()
138 let file = ref None
in
141 | None
-> file := Some f
142 | Some _
-> usage_and_exit ()
144 let skip_if_errors = ref false in
145 let expect_extension = ref ".exp" in
146 let set_expect_extension s
= expect_extension := s
in
147 let auto_namespace_map = ref [] in
148 let enable_xhp_class_modifier = ref false in
149 let disable_xhp_element_mangling = ref false in
150 let enable_enum_classes = ref false in
151 let ignored_flag flag
= (flag
, Arg.Unit
(fun _
-> ()), "(ignored)") in
152 let ignored_arg flag
= (flag
, Arg.String
(fun _
-> ()), "(ignored)") in
155 ( "--compare-direct-decl-parser",
156 Arg.Unit
(set_mode CompareDirectDeclParser
),
157 "(mode) Runs the direct decl parser against the FFP -> naming -> decl pipeline and compares their output"
159 ( "--skip-if-errors",
160 Arg.Set
skip_if_errors,
161 "Skip comparison if the corresponding .exp file has errors" );
162 ( "--expect-extension",
163 Arg.String
set_expect_extension,
164 "The extension with which the output of the legacy pipeline should be written"
166 ( "--auto-namespace-map",
169 auto_namespace_map := ServerConfig.convert_auto_namespace_to_map m
),
170 "Namespace aliases" );
171 ( "--enable-xhp-class-modifier",
172 Arg.Set
enable_xhp_class_modifier,
173 "Enable the XHP class modifier, xhp class name {} will define an xhp class."
175 ( "--disable-xhp-element-mangling",
176 Arg.Set
disable_xhp_element_mangling,
178 ( "--enable-enum-classes",
179 Arg.Set
enable_enum_classes,
180 "Enable the enum classes extension." );
181 (* The following options do not affect the direct decl parser and can be ignored
182 (they are used by hh_single_type_check, and we run hh_single_decl over all of
183 the typecheck test cases). *)
184 ignored_flag "--abstract-static-props";
185 ignored_arg "--allowed-decl-fixme-codes";
186 ignored_arg "--allowed-fixme-codes-strict";
187 ignored_flag "--allow-toplevel-requires";
188 ignored_flag "--check-xhp-attribute";
189 ignored_flag "--complex-coercion";
190 ignored_flag "--const-attribute";
191 ignored_flag "--const-static-props";
192 ignored_flag "--disable-hh-ignore-error";
193 ignored_flag "--disable-modes";
194 ignored_flag "--disable-partially-abstract-typeconsts";
195 ignored_flag "--disable-unset-class-const";
196 ignored_flag "--disable-xhp-children-declarations";
197 ignored_flag "--disallow-discarded-nullable-awaitables";
198 ignored_flag "--disallow-fun-and-cls-meth-pseudo-funcs";
199 ignored_flag "--disallow-func-ptrs-in-constants";
200 ignored_flag "--disallow-invalid-arraykey-constraint";
201 ignored_flag "--disallow-php-lambdas";
202 ignored_flag "--disallow-silence";
203 ignored_flag "--disallow-trait-reuse";
204 ignored_flag "--enable-class-level-where-clauses";
205 ignored_flag "--enable-higher-kinded-types";
206 ignored_flag "--enable-systemlib-annotations";
207 ignored_flag "--forbid_nullable_cast";
209 Arg.Tuple
[Arg.String
(fun _
-> ()); Arg.String
(fun _
-> ())],
211 ignored_flag "--like-casts";
212 ignored_flag "--like-type-hints";
213 ignored_flag "--like-types-all";
214 ignored_flag "--method-call-inference";
215 ignored_flag "--no-builtins";
216 ignored_flag "--no-strict-contexts";
217 ignored_flag "--report-pos-from-reason";
218 ignored_arg "--simple-pessimize";
219 ignored_arg "--timeout";
220 ignored_flag "--union-intersection-type-hints";
225 | None
-> usage_and_exit ()
226 | Some CompareDirectDeclParser
->
229 | None
-> usage_and_exit ()
235 @@ String_utils.is_substring
237 (RealDisk.cat
(file ^
".exp"))
239 print_endline
"Skipping because input file has errors";
243 let file = Path.make
file in
244 let auto_namespace_map = !auto_namespace_map in
245 let enable_xhp_class_modifier = !enable_xhp_class_modifier in
246 let disable_xhp_element_mangling = !disable_xhp_element_mangling in
247 let enable_enum_classes = !enable_enum_classes in
251 ~
enable_xhp_class_modifier
252 ~
disable_xhp_element_mangling
255 let ctx = init (Path.dirname
file) popt in
256 let file = Relative_path.(create Root
(Path.to_string
file)) in
257 let files = Multifile.file_to_file_list
file in
258 let num_files = List.length
files in
259 let (all_matched
, _
) =
263 ~f
:(fun (matched, is_first
) (filename
, contents
) ->
264 (* All output is printed to stderr because that's the output
265 channel Ppxlib_print_diff prints to. *)
266 if not is_first
then Printf.eprintf
"\n%!";
267 (* Multifile turns the path into an absolute path instead of a
268 relative one. Turn it back into a relative path. *)
270 Relative_path.(create Root
(Relative_path.to_absolute
filename))
272 if num_files > 1 then
275 (Relative_path.storage_to_string
filename);
277 Provider_utils.respect_but_quarantine_unsaved_changes
279 ~f
:(fun () -> compare_decls ctx filename contents
)
285 Printf.eprintf
"\nThey matched!\n%!"