2 * Copyright (c) 2016, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
12 * Usage: hh_parse [OPTIONS] [FILES]
14 * --full-fidelity-json
15 * --full-fidelity-errors
16 * --full-fidelity-errors-all
17 * --full-fidelity-s-expression
18 * --full-fidelity-ast-s-expression
23 * TODO: Parser for things other than scripts:
24 * types, expressions, statements, declarations, etc.
27 module Schema
= Full_fidelity_schema
28 module SyntaxError
= Full_fidelity_syntax_error
29 module SyntaxTree
= Full_fidelity_syntax_tree
30 .WithSyntax
(Full_fidelity_positioned_syntax
)
31 module SourceText
= Full_fidelity_source_text
32 module ParserErrors
= Full_fidelity_parser_errors
33 .WithSyntax
(Full_fidelity_positioned_syntax
)
34 module DebugPos
= Debug.WithSyntax
(Full_fidelity_positioned_syntax
)
36 module FullFidelityParseArgs
= struct
41 full_fidelity_json
: bool;
42 full_fidelity_text_json
: bool;
43 full_fidelity_dot
: bool;
44 full_fidelity_dot_edges
: bool;
45 full_fidelity_errors
: bool;
46 full_fidelity_errors_all
: bool;
47 full_fidelity_s_expr
: bool;
48 full_fidelity_ast_s_expr
: bool;
52 show_file_name
: bool;
53 (* Configuring the parser *)
56 php5_compat_mode
: bool;
57 elaborate_namespaces
: bool;
58 include_line_comments
: bool;
61 lower_coroutines
: bool;
62 enable_hh_syntax
: bool;
63 enable_await_as_an_expression
: bool;
65 (* Defining the input *)
68 enable_stronger_await_binding
: bool;
69 pocket_universes
: bool;
74 full_fidelity_text_json
76 full_fidelity_dot_edges
78 full_fidelity_errors_all
80 full_fidelity_ast_s_expr
93 enable_await_as_an_expression
98 enable_stronger_await_binding
102 full_fidelity_dot_edges
;
103 full_fidelity_text_json
;
104 full_fidelity_errors
;
105 full_fidelity_errors_all
;
106 full_fidelity_s_expr
;
107 full_fidelity_ast_s_expr
;
114 elaborate_namespaces
;
115 include_line_comments
;
120 enable_await_as_an_expression
;
125 enable_stronger_await_binding
;
130 let usage = Printf.sprintf
"Usage: %s [OPTIONS] filename\n" Sys.argv
.(0) in
131 let full_fidelity_json = ref false in
132 let set_full_fidelity_json () = full_fidelity_json := true in
133 let full_fidelity_text_json = ref false in
134 let set_full_fidelity_text_json () = full_fidelity_text_json := true in
135 let full_fidelity_dot = ref false in
136 let set_full_fidelity_dot () = full_fidelity_dot := true in
137 let full_fidelity_dot_edges = ref false in
138 let set_full_fidelity_dot_edges () = full_fidelity_dot_edges := true in
139 let full_fidelity_errors = ref false in
140 let set_full_fidelity_errors () = full_fidelity_errors := true in
141 let full_fidelity_errors_all = ref false in
142 let set_full_fidelity_errors_all () =
143 full_fidelity_errors_all := true in
144 let full_fidelity_s_expr = ref false in
145 let full_fidelity_ast_s_expr = ref false in
146 let set_full_fidelity_s_expr () = full_fidelity_s_expr := true in
147 let set_full_fidelity_ast_s_expr () = full_fidelity_ast_s_expr := true in
148 let program_text = ref false in
149 let set_program_text () = program_text := true in
150 let pretty_print = ref false in
151 let set_pretty_print () = pretty_print := true in
152 let schema = ref false in
153 let set_schema () = schema := true in
154 let is_hh_file = ref false in
155 let codegen = ref false in
156 let php5_compat_mode = ref false in
157 let elaborate_namespaces = ref true in
158 let include_line_comments = ref false in
159 let keep_errors = ref true in
160 let quick_mode = ref false in
161 let lower_coroutines = ref true in
162 let enable_hh_syntax = ref false in
163 let enable_await_as_an_expression = ref false in
164 let fail_open = ref true in
165 let show_file_name = ref false in
166 let dump_nast = ref false in
167 let enable_stronger_await_binding = ref false in
168 let set_show_file_name () = show_file_name := true in
169 let pocket_universes = ref false in
170 let files = ref [] in
171 let push_file file
= files := file
:: !files in
174 "--full-fidelity-json",
175 Arg.Unit
set_full_fidelity_json,
176 "Displays the full-fidelity parse tree in JSON format.";
177 "--full-fidelity-text-json",
178 Arg.Unit
set_full_fidelity_text_json,
179 "Displays the full-fidelity parse tree in JSON format with token text.";
180 "--full-fidelity-dot",
181 Arg.Unit
set_full_fidelity_dot,
182 "Displays the full-fidelity parse tree in GraphViz DOT format.";
183 "--full-fidelity-dot-edges",
184 Arg.Unit
set_full_fidelity_dot_edges,
185 "Displays the full-fidelity parse tree in GraphViz DOT format with edge labels.";
186 "--full-fidelity-errors",
187 Arg.Unit
set_full_fidelity_errors,
188 "Displays the full-fidelity parser errors, if any.
189 Some errors may be filtered out.";
190 "--full-fidelity-errors-all",
191 Arg.Unit
set_full_fidelity_errors_all,
192 "Displays the full-fidelity parser errors, if any.
193 No errors are filtered out.";
194 "--full-fidelity-s-expression",
195 Arg.Unit
set_full_fidelity_s_expr,
196 "Displays the full-fidelity parse tree in S-expression format.";
197 "--full-fidelity-ast-s-expression",
198 Arg.Unit
set_full_fidelity_ast_s_expr,
199 "Displays the AST produced by the FFP in S-expression format.";
201 Arg.Unit
set_program_text,
202 "Displays the text of the given file.";
204 Arg.Unit
set_pretty_print,
205 "Displays the text of the given file after pretty-printing.";
208 "Displays the parser version and schema of nodes.";
211 "Set the is_hh_file option for the parser.";
213 Arg.Clear
is_hh_file,
214 "Unset the is_hh_file option for the parser.";
217 "Set the codegen option for the parser.";
220 "Unset the codegen option for the parser.";
221 "--php5-compat-mode",
222 Arg.Set
php5_compat_mode,
223 "Set the php5_compat_mode option for the parser.";
224 "--no-php5-compat-mode",
225 Arg.Clear
php5_compat_mode,
226 "Unset the php5_compat_mode option for the parser.";
227 "--elaborate-namespaces",
228 Arg.Set
elaborate_namespaces,
229 "Set the elaborate_namespaces option for the parser.";
230 "--no-elaborate-namespaces",
231 Arg.Clear
elaborate_namespaces,
232 "Unset the elaborate_namespaces option for the parser.";
233 "--include-line-comments",
234 Arg.Set
include_line_comments,
235 "Set the include_line_comments option for the parser.";
236 "--no-include-line-comments",
237 Arg.Clear
include_line_comments,
238 "Unset the include_line_comments option for the parser.";
241 "Set the keep_errors option for the parser.";
243 Arg.Clear
keep_errors,
244 "Unset the keep_errors option for the parser.";
247 "Set the quick_mode option for the parser.";
249 Arg.Clear
quick_mode,
250 "Unset the quick_mode option for the parser.";
251 "--lower-coroutines",
252 Arg.Set
lower_coroutines,
253 "Set the lower_coroutines option for the parser.";
254 "--no-lower-coroutines",
255 Arg.Clear
lower_coroutines,
256 "Unset the lower_coroutines option for the parser.";
259 "Set the fail_open option for the parser.";
262 "Unset the fail_open option for the parser.";
264 Arg.Set
enable_hh_syntax,
265 "Force hh syntax for the parser.";
266 "--enable-await-as-an-expression",
267 Arg.Set
enable_await_as_an_expression,
268 "Enable await-as-an-expression";
270 Arg.Unit
set_show_file_name,
271 "Displays the file name.";
274 "Converts the legacy AST to a NAST and prints it.";
275 "--stronger-await-binding",
276 Arg.Set
enable_stronger_await_binding,
277 "Increases precedence of await during parsing.";
278 "--pocket-universes",
279 Arg.Set
pocket_universes,
280 "Enables support for Pocket Universes";
282 Arg.parse
options push_file usage;
285 !full_fidelity_text_json
287 !full_fidelity_dot_edges
288 !full_fidelity_errors
289 !full_fidelity_errors_all
290 !full_fidelity_s_expr
291 !full_fidelity_ast_s_expr
298 !elaborate_namespaces
299 !include_line_comments
304 !enable_await_as_an_expression
309 !enable_stronger_await_binding
313 open FullFidelityParseArgs
315 let print_error error
= error
316 |> Errors.to_absolute
318 |> output_string stdout
320 (* Prints a single FFP error. *)
321 let print_full_fidelity_error source_text error
=
322 let text = SyntaxError.to_positioned_string
323 error
(SourceText.offset_to_position source_text
) in
324 Printf.printf
"%s\n" text
326 (* Computes and prints list of all FFP errors from syntax pass and parser pass.
327 * Specifying all_errors=false will attempt to filter out duplicate errors. *)
328 let print_full_fidelity_errors ~source_text ~error_env
=
329 let errors = ParserErrors.parse_errors error_env
in
330 List.iter
(print_full_fidelity_error source_text
) errors
332 let handle_existing_file args filename
=
333 let popt = ParserOptions.default
in
334 let popt = ParserOptions.with_hh_syntax_for_hhvm
popt
335 (args
.codegen && args
.enable_hh_syntax) in
336 let popt = ParserOptions.with_enable_await_as_an_expression
popt
337 (args
.enable_await_as_an_expression) in
339 (* Parse with the full fidelity parser *)
340 let file = Relative_path.create
Relative_path.Dummy filename
in
341 let suffix = Relative_path.suffix file in
342 let source_text = SourceText.from_file
file in
343 let mode = Full_fidelity_parser.parse_mode
source_text in
344 let env = Full_fidelity_parser_env.make
345 ~force_hh
:args
.enable_hh_syntax
346 ~enable_xhp
:args
.enable_hh_syntax
347 ~
enable_stronger_await_binding:args
.enable_stronger_await_binding
348 ~has_dot_hack_extension
:(String_utils.string_ends_with
suffix ".hack")
350 let syntax_tree = SyntaxTree.make ~
env source_text in
351 let editable = SyntaxTransforms.editable_from_positioned
syntax_tree in
353 if args
.show_file_name then begin
354 Printf.printf
"%s\n" filename
356 if args
.program_text then begin
357 let text = Full_fidelity_editable_syntax.text editable in
358 Printf.printf
"%s\n" text
360 if args
.pretty_print then begin
361 let pretty = Libhackfmt.format_tree
syntax_tree in
362 Printf.printf
"%s\n" pretty
367 || args
.full_fidelity_errors
368 || args
.full_fidelity_errors_all
370 if print_errors then begin
371 let level = if args
.full_fidelity_errors_all
372 then ParserErrors.Maximum
373 else ParserErrors.Typical
in
374 let hhvm_compat_mode = if args
.codegen
375 then ParserErrors.HHVMCompat
376 else ParserErrors.NoCompat
in
377 let error_env = ParserErrors.make_env
syntax_tree
380 ~
codegen:args
.codegen
383 print_full_fidelity_errors ~
source_text ~
error_env
386 if args
.full_fidelity_s_expr then begin
387 let root = SyntaxTree.root syntax_tree in
388 let str = DebugPos.dump_syntax
root in
389 Printf.printf
"%s\n" str
391 if args
.full_fidelity_ast_s_expr || args
.dump_nast then begin
392 let module Lowerer
= Full_fidelity_ast
in
395 then { popt with GlobalOptions.po_enable_concurrent
= true }
399 ~
codegen:args
.codegen
400 ~
php5_compat_mode:args
.php5_compat_mode
401 ~
elaborate_namespaces:args
.elaborate_namespaces
402 ~
include_line_comments:args
.include_line_comments
403 ~
keep_errors:args
.keep_errors
404 ~
quick_mode:args
.quick_mode
405 ~
lower_coroutines:args
.lower_coroutines
406 ~
enable_hh_syntax:args
.enable_hh_syntax
407 ~enable_xhp
:args
.enable_hh_syntax
409 ~
fail_open:args
.fail_open
410 ~
is_hh_file:args
.is_hh_file
411 ~
pocket_universes:args
.pocket_universes
414 let res = Lowerer.from_file
env in
415 let ast = res.Lowerer.ast in
417 if args
.dump_nast then
418 Nast.show_program
(Ast_to_nast.convert
ast)
420 Debug.dump_ast
(Ast.AProgram
ast) in
421 Printf.printf
"%s\n" str
423 if args
.full_fidelity_json then begin
424 let json = SyntaxTree.to_json
syntax_tree in
425 let str = Hh_json.json_to_string
json in
426 Printf.printf
"%s\n" str
428 if args
.full_fidelity_text_json then begin
429 let json = Full_fidelity_editable_syntax.to_json
editable in
430 let str = Hh_json.json_to_string
json in
431 Printf.printf
"%s\n" str
433 if args
.full_fidelity_dot then begin
434 let dot = Full_fidelity_editable_syntax.to_dot
editable false in
435 Printf.printf
"%s\n" dot
437 if args
.full_fidelity_dot_edges then begin
438 let dot = Full_fidelity_editable_syntax.to_dot
editable true in
439 Printf.printf
"%s\n" dot
442 let handle_file args filename
=
443 if Path.file_exists
(Path.make filename
) then
444 handle_existing_file args filename
446 Printf.printf
"File %s does not exist.\n" filename
448 let rec main args
files =
449 if args
.schema then begin
450 let schema = Schema.schema_as_json
() in
451 Printf.printf
"%s\n" schema
457 Unix.handle_unix_error
(handle_file args
) file;
462 let args = parse_args () in
463 EventLogger.init
EventLogger.Event_logger_fake
0.0;
464 let handle = SharedMem.init ~num_workers
:0 GlobalConfig.default_sharedmem_config
in
465 ignore
(handle: SharedMem.handle);