disallow keywords as identifiers
[hiphop-php.git] / hphp / hack / src / parser / full_fidelity_statement_parser.ml
blobe309a7b71d76e34da2d9de804cb3dbbe96dd1e8e
1 (**
2 * Copyright (c) 2016, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
9 module WithSyntax(Syntax: Syntax_sig.Syntax_S) = struct
10 module Token = Syntax.Token
11 module Trivia = Token.Trivia
12 module TriviaKind = Full_fidelity_trivia_kind
13 module SyntaxKind = Full_fidelity_syntax_kind
14 module TokenKind = Full_fidelity_token_kind
15 module SourceText = Full_fidelity_source_text
16 module SyntaxError = Full_fidelity_syntax_error
17 module Env = Full_fidelity_parser_env
18 module SimpleParserSyntax =
19 Full_fidelity_simple_parser.WithSyntax(Syntax)
20 module SimpleParser = SimpleParserSyntax.WithLexer(
21 Full_fidelity_lexer.WithToken(Syntax.Token))
23 module ParserHelperSyntax = Full_fidelity_parser_helpers.WithSyntax(Syntax)
24 module ParserHelper = ParserHelperSyntax
25 .WithLexer(Full_fidelity_lexer.WithToken(Syntax.Token))
26 module type SCWithKind_S = SmartConstructorsWrappers.SyntaxKind_S
28 module type ExpressionParser_S = Full_fidelity_expression_parser_type
29 .WithSyntax(Syntax)
30 .WithLexer(Full_fidelity_lexer.WithToken(Syntax.Token))
31 .ExpressionParser_S
33 module type DeclarationParser_S = Full_fidelity_declaration_parser_type
34 .WithSyntax(Syntax)
35 .WithLexer(Full_fidelity_lexer.WithToken(Syntax.Token))
36 .DeclarationParser_S
38 module type TypeParser_S = Full_fidelity_type_parser_type
39 .WithSyntax(Syntax)
40 .WithLexer(Full_fidelity_lexer.WithToken(Syntax.Token))
41 .TypeParser_S
43 module type StatementParser_S = Full_fidelity_statement_parser_type
44 .WithSyntax(Syntax)
45 .WithLexer(Full_fidelity_lexer.WithToken(Syntax.Token))
46 .StatementParser_S
48 open TokenKind
49 open Syntax
51 module WithSmartConstructors (SCI : SCWithKind_S with module Token = Syntax.Token)
52 = struct
54 module WithExpressionAndDeclAndTypeParser
55 (ExpressionParser : ExpressionParser_S with module SC = SCI)
56 (DeclParser : DeclarationParser_S with module SC = SCI)
57 (TypeParser : TypeParser_S with module SC = SCI) :
58 (StatementParser_S with module SC = SCI) = struct
60 module Parser = SimpleParser.WithSmartConstructors (SCI)
61 include Parser
62 include ParserHelper.WithParser(Parser)
64 let parse_type_specifier parser =
65 let type_parser =
66 TypeParser.make
67 parser.env
68 parser.lexer
69 parser.errors
70 parser.context
71 parser.sc_state in
72 let (type_parser, spec) = TypeParser.parse_type_specifier type_parser in
73 let env = TypeParser.env type_parser in
74 let lexer = TypeParser.lexer type_parser in
75 let errors = TypeParser.errors type_parser in
76 let context = TypeParser.context type_parser in
77 let sc_state = TypeParser.sc_state type_parser in
78 let parser = { env; lexer; errors; context; sc_state } in
79 (parser, spec)
81 let with_expr_parser
82 : 'a . t -> (ExpressionParser.t -> ExpressionParser.t * 'a) -> t * 'a
83 = fun parser f ->
84 let expr_parser =
85 ExpressionParser.make
86 parser.env
87 parser.lexer
88 parser.errors
89 parser.context
90 parser.sc_state in
91 let (expr_parser, node) = f expr_parser in
92 let env = ExpressionParser.env expr_parser in
93 let lexer = ExpressionParser.lexer expr_parser in
94 let errors = ExpressionParser.errors expr_parser in
95 let context = ExpressionParser.context expr_parser in
96 let sc_state = ExpressionParser.sc_state expr_parser in
97 let parser = { env; lexer; errors; context; sc_state } in
98 (parser, node)
100 let parse_expression parser =
101 with_expr_parser parser ExpressionParser.parse_expression
103 let with_decl_parser : 'a . t -> (DeclParser.t -> DeclParser.t * 'a) -> t * 'a
104 = fun parser f ->
105 let decl_parser =
106 DeclParser.make
107 parser.env
108 parser.lexer
109 parser.errors
110 parser.context
111 parser.sc_state
113 let (decl_parser, node) = f decl_parser in
114 let env = DeclParser.env decl_parser in
115 let lexer = DeclParser.lexer decl_parser in
116 let errors = DeclParser.errors decl_parser in
117 let context = DeclParser.context decl_parser in
118 let sc_state = DeclParser.sc_state decl_parser in
119 let parser = { env; lexer; errors; context; sc_state } in
120 (parser, node)
122 let rec parse_statement parser =
123 match peek_token_kind parser with
124 | Async
125 | Coroutine
126 | Function -> parse_possible_php_function parser
127 | Abstract
128 | Final
129 | Interface
130 | Trait
131 | Class -> parse_php_class parser
132 | Fallthrough -> parse_possible_erroneous_fallthrough parser
133 | For -> parse_for_statement parser
134 | Foreach -> parse_foreach_statement parser
135 | Do -> parse_do_statement parser
136 | While -> parse_while_statement parser
137 | Declare -> parse_declare_statement parser
138 | Let when Env.is_experimental_mode (env parser) -> parse_let_statement parser
139 | Using ->
140 let (parser, missing) = Make.missing parser (pos parser) in
141 parse_using_statement parser missing
142 | Await when peek_token_kind ~lookahead:1 parser = Using ->
143 let parser, await_kw = assert_token parser Await in
144 parse_using_statement parser await_kw
145 | If -> parse_if_statement parser
146 | Switch -> parse_switch_statement parser
147 | Try -> parse_try_statement parser
148 | Break -> parse_break_statement parser
149 | Continue -> parse_continue_statement parser
150 | Return -> parse_return_statement parser
151 | Throw -> parse_throw_statement parser
152 | LeftBrace -> parse_compound_statement parser
153 | Static ->
154 parse_function_static_declaration_or_expression_statement parser
155 | Echo -> parse_echo_statement parser
156 | Global -> parse_global_statement_or_expression_statement parser
157 | Unset -> parse_unset_statement parser
158 | Case ->
159 let (parser, result) = parse_case_label parser in
160 (* TODO: This puts the error in the wrong place. We should highlight
161 the entire label, not the trailing colon. *)
162 let parser = with_error parser SyntaxError.error2003 in
163 (parser, result)
164 | Default ->
165 let (parser, result) = parse_default_label parser in
166 (* TODO: This puts the error in the wrong place. We should highlight
167 the entire label, not the trailing colon. *)
168 let parser = with_error parser SyntaxError.error2004 in
169 (parser, result)
170 | Name when peek_token_kind ~lookahead:1 parser = Colon ->
171 parse_goto_label parser
172 | Goto -> parse_goto_statement parser
173 | QuestionGreaterThan ->
174 let (p, s, _) = parse_markup_section parser ~is_leading_section:false in
175 (p, s)
176 | Semicolon -> parse_expression_statement parser
177 (* ERROR RECOVERY: when encountering a token that's invalid now but the
178 * context says is expected later, make the whole statement missing
179 * and continue on, starting at the unexpected token. *)
180 (* TODO T20390825: Make sure this this won't cause premature recovery. *)
181 | kind when Parser.expects parser kind ->
182 Make.missing parser (pos parser)
183 | _ -> parse_expression_statement parser
185 and parse_markup_section parser ~is_leading_section =
186 let parser, prefix =
187 (* for markup section at the beginning of the file
188 treat ?> as a part of markup text *)
189 (* The closing ?> tag is not legal hack, but accept it here and give an
190 error in a later pass *)
191 if not is_leading_section
192 && peek_token_kind parser = TokenKind.QuestionGreaterThan then
193 fetch_token parser
194 else
195 Make.missing parser (pos parser)
197 let parser, markup, suffix_opt = scan_markup parser ~is_leading_section in
198 let (parser, markup) = Make.token parser markup in
199 let (parser, suffix, is_echo_tag, has_suffix) =
200 match suffix_opt with
201 | Some (less_than_question, language_opt) ->
202 let (parser, less_than_question_token) =
203 Make.token parser less_than_question
205 (* if markup section ends with <?= tag
206 then script section embedded between tags should be treated as if it
207 will be an argument to 'echo'. Technically it should be restricted to
208 expression but since it permits trailing semicolons we parse it as
209 expression statement.
210 TODO: consider making it even more loose and parse it as declaration
211 for better error recovery in cases when user
212 accidentally type '<?=' instead of '<?php' so declaration in script
213 section won't throw parser off the rails. *)
214 let (parser, language, is_echo_tag) =
215 match language_opt with
216 | Some language ->
217 let (parser, token) = Make.token parser language in
218 (parser, token, (Token.kind language = TokenKind.Equal))
219 | None ->
220 let (parser, missing) = Make.missing parser (pos parser) in
221 (parser, missing, false)
223 let (parser, suffix) =
224 Make.markup_suffix parser less_than_question_token language
226 ( parser
227 , suffix
228 , is_echo_tag
229 , true
231 | None ->
232 let (parser, missing) = Make.missing parser (pos parser) in
233 (parser, missing, false, false)
235 let parser, expression =
236 if is_echo_tag then parse_statement parser
237 else Make.missing parser (pos parser)
239 let (parser, s) =
240 Make.markup_section parser prefix markup suffix expression
242 (parser, s, has_suffix)
244 and parse_possible_php_function parser =
245 (* ERROR RECOVERY: PHP supports nested named functions, but Hack does not.
246 (Hack only supports anonymous nested functions as expressions.)
248 If we have a statement beginning with function left-paren, then parse it
249 as a statement expression beginning with an anonymous function; it will
250 then have to end with a semicolon.
252 If it starts with something else, parse it as a function.
254 TODO: Give an error for nested nominal functions in a later pass.
257 let kind0 = peek_token_kind ~lookahead:0 parser in
258 let kind1 = peek_token_kind ~lookahead:1 parser in
259 match kind0, kind1 with
260 | (Async | Coroutine), Function
261 when peek_token_kind ~lookahead:2 parser = LeftParen ->
262 parse_expression_statement parser
263 | Function, LeftParen (* Verbose-style lambda *)
264 | (Async | Coroutine), LeftParen (* Async / coroutine, compact-style lambda *)
265 | Async, LeftBrace (* Async block *)
266 -> parse_expression_statement parser
267 | _ ->
268 let (parser, missing) = Make.missing parser (pos parser) in
269 with_decl_parser
270 parser
271 (fun p ->
272 DeclParser.parse_function_declaration p missing)
274 and parse_php_class parser =
275 (* PHP allows classes nested inside of functions, but hack does not *)
276 (* TODO check for hack error: no classish declarations inside functions *)
277 let (parser, missing) = Make.missing parser (pos parser) in
278 with_decl_parser parser
279 (fun parser -> DeclParser.parse_classish_declaration parser missing)
281 (* Helper: parses ( expr ) *)
282 and parse_paren_expr parser =
283 let (parser, left_paren) = require_left_paren parser in
284 let (parser, expr_syntax) = parse_expression parser in
285 let (parser, right_paren) = require_right_paren parser in
286 (parser, left_paren, expr_syntax, right_paren)
288 and parse_for_statement parser =
289 (* SPEC
290 for-statement:
291 for ( for-initializer-opt ; for-control-opt ; \
292 for-end-of-loop-opt ) statement
294 Each clause is an optional, comma-separated list of expressions.
295 Note that unlike most such lists in Hack, it may *not* have a trailing
296 comma.
297 TODO: There is no compelling reason to not allow a trailing comma
298 from the grammatical point of view. Each clause unambiguously ends in
299 either a semi or a paren, so we can allow a trailing comma without
300 difficulty.
303 let parser, for_keyword_token = assert_token parser For in
304 let parser, for_left_paren = require_left_paren parser in
305 let parser, for_initializer_expr = parse_comma_list_opt
306 parser Semicolon SyntaxError.error1015 parse_expression in
307 let parser, for_first_semicolon = require_semicolon parser in
308 let parser, for_control_expr = parse_comma_list_opt
309 parser Semicolon SyntaxError.error1015 parse_expression in
310 let parser, for_second_semicolon = require_semicolon parser in
311 let parser, for_end_of_loop_expr = parse_comma_list_opt
312 parser RightParen SyntaxError.error1015 parse_expression in
313 let parser, for_right_paren = require_right_paren parser in
314 let parser, for_statement =
315 let _, open_token = next_token parser in
316 match Token.kind open_token with
317 | Colon -> parse_alternate_loop_statement parser ~terminator:Endfor
318 | _ -> parse_statement parser
320 Make.for_statement
321 parser
322 for_keyword_token
323 for_left_paren
324 for_initializer_expr
325 for_first_semicolon
326 for_control_expr
327 for_second_semicolon
328 for_end_of_loop_expr
329 for_right_paren
330 for_statement
332 and parse_foreach_statement parser =
333 let parser, foreach_keyword_token = assert_token parser Foreach in
334 let parser, foreach_left_paren = require_left_paren parser in
335 let parser = Parser.expect_in_new_scope parser [ RightParen ] in
336 let parser, foreach_collection_name =
337 with_expr_parser parser (fun p ->
338 ExpressionParser.with_as_expresssions p ~enabled:false ExpressionParser.parse_expression
339 ) in
340 let parser, await_token = optional_token parser Await in
341 let parser, as_token = require_as parser in
342 let (parser1, after_as) = parse_expression parser in
343 let (parser, foreach_key, foreach_arrow, foreach_value) =
344 match Token.kind (peek_token parser1) with
345 | RightParen ->
346 let (parser, missing1) = Make.missing parser (pos parser) in
347 let (parser, missing2) = Make.missing parser (pos parser) in
348 let (parser, value) = parse_expression parser in
349 (parser, missing1, missing2, value)
350 | EqualGreaterThan ->
351 let parser, arrow = assert_token parser1 EqualGreaterThan in
352 let parser, value = parse_expression parser in
353 (parser, after_as, arrow, value)
354 | _ ->
355 let parser = with_error parser1 SyntaxError.invalid_foreach_element in
356 let (parser, token) = fetch_token parser in
357 let (parser, error) = Make.error parser token in
358 let (parser, foreach_value) = parse_expression parser in
359 (parser, after_as, error, foreach_value)
361 let parser, right_paren_token = require_right_paren parser in
362 let parser = Parser.pop_scope parser [ RightParen ] in
363 let parser, foreach_statement =
364 match peek_token_kind parser with
365 | Colon -> parse_alternate_loop_statement parser ~terminator:Endforeach
366 | _ -> parse_statement parser
368 Make.foreach_statement
369 parser
370 foreach_keyword_token
371 foreach_left_paren
372 foreach_collection_name
373 await_token
374 as_token
375 foreach_key
376 foreach_arrow
377 foreach_value
378 right_paren_token
379 foreach_statement
381 and parse_do_statement parser =
382 let (parser, do_keyword_token) =
383 assert_token parser Do in
384 let (parser, statement_node) =
385 parse_statement parser in
386 let (parser, do_while_keyword_token) = require_while parser in
387 let (parser, left_paren_token, expr_node, right_paren_token) =
388 parse_paren_expr parser in
389 let (parser, do_semicolon_token) = require_semicolon parser in
390 Make.do_statement
391 parser
392 do_keyword_token
393 statement_node
394 do_while_keyword_token
395 left_paren_token
396 expr_node
397 right_paren_token
398 do_semicolon_token
400 and parse_while_statement parser =
401 let (parser, while_keyword_token) = assert_token parser While in
402 let (parser, left_paren_token, expr_node, right_paren_token) =
403 parse_paren_expr parser
405 let (parser, statement_node) =
406 match peek_token_kind parser with
407 | Colon -> parse_alternate_loop_statement parser ~terminator:Endwhile
408 | _ -> parse_statement parser
410 Make.while_statement
411 parser
412 while_keyword_token
413 left_paren_token
414 expr_node
415 right_paren_token
416 statement_node
418 (* SPEC:
419 let-statement:
420 let name = expression ;
421 let name : type = expression ;
423 and parse_let_statement parser =
424 let (parser, let_keyword_token) = assert_token parser Let in
425 let (parser, name_token) = require_name parser in
426 let (parser, colon_token, type_token) =
427 match peek_token_kind parser with
428 | Colon ->
429 let (parser, colon_token) = assert_token parser Colon in
430 let (parser, type_token) = parse_type_specifier parser in
431 parser, colon_token, type_token
432 | _ ->
433 let (parser, missing_colon) = Make.missing parser (pos parser) in
434 let (parser, missing_type) = Make.missing parser (pos parser) in
435 parser, missing_colon, missing_type
437 let (parser, equal_token) = require_equal parser in
438 let (parser, expr_node) = parse_expression parser in
439 let (parser, init_node) =
440 Make.simple_initializer parser equal_token expr_node
442 let (parser, semi_token) = require_semicolon parser in
443 Make.let_statement
444 parser
445 let_keyword_token
446 name_token
447 colon_token
448 type_token
449 init_node
450 semi_token
452 (* SPEC:
453 declare-statement:
454 declare ( expression ) ;
455 declare ( expression ) compound-statement
457 declare ( expression ):
458 compound-statement enddeclare;
459 TODO: Update the specification of the grammar
461 and parse_declare_statement parser =
462 let (parser, declare_keyword_token) =
463 assert_token parser Declare in
464 let (parser, left_paren_token, expr_node, right_paren_token) =
465 parse_paren_expr parser in
466 match peek_token_kind parser with
467 | Semicolon ->
468 let (parser, semi) = assert_token parser Semicolon in
469 Make.declare_directive_statement
470 parser
471 declare_keyword_token
472 left_paren_token
473 expr_node
474 right_paren_token
475 semi
476 | Colon ->
477 let (parser, statement_node) =
478 parse_alternate_loop_statement parser ~terminator:Enddeclare
480 Make.declare_block_statement
481 parser
482 declare_keyword_token
483 left_paren_token
484 expr_node
485 right_paren_token
486 statement_node
487 | _ ->
488 let (parser, statement_node) = parse_statement parser in
489 Make.declare_block_statement
490 parser
491 declare_keyword_token
492 left_paren_token
493 expr_node
494 right_paren_token
495 statement_node
497 (* SPEC:
498 using-statement:
499 await-opt using expression ;
500 await-opt using ( expression-list ) compound-statement
502 TODO: Update the specification of the grammar
504 and parse_using_statement parser await_kw =
505 let (parser, using_kw) = assert_token parser Using in
506 (* Decision point - Are we at a function scope or a body scope *)
507 let token_kind = peek_token_kind parser in
508 (* if next token is left paren it can be either
509 - parenthesized expression followed by semicolon for function scoped using
510 - comma separated list of expressions wrapped in parens for blocks.
511 To distinguish between then try parse parenthesized expression and then
512 check next token. NOTE: we should not use 'parse_expression' here
513 since it might parse (expr) { smth() } as subscript expression $expr{$index}
515 let (parser1, expr) =
516 if token_kind = LeftParen then
517 with_expr_parser parser
518 ExpressionParser.parse_cast_or_parenthesized_or_lambda_expression
519 else parse_expression parser in
520 let (parser1, token) = next_token parser1 in
521 match Token.kind token with
522 | Semicolon ->
523 let (parser, semi) = Make.token parser1 token in
524 Make.using_statement_function_scoped parser await_kw using_kw expr semi
525 | _ ->
526 let (parser, left_paren) = require_left_paren parser in
527 let (parser, expressions) = parse_comma_list
528 parser RightParen SyntaxError.error1015 parse_expression
530 let (parser, right_paren) = require_right_paren parser in
531 let (parser, statements) = parse_statement parser in
532 Make.using_statement_block_scoped parser await_kw using_kw left_paren
533 expressions right_paren statements
535 and parse_unset_statement parser =
537 TODO: This is listed as unsupported in Hack in the spec; is that true?
538 TODO: If it is formally supported in Hack then update the spec; if not
539 TODO: then should we make it illegal in strict mode?
540 TODO: Can the list be comma-terminated?
541 TODO: Can the list be empty?
542 TODO: The list has to be expressions which evaluate as variables;
543 add an error checking pass.
544 TODO: Unset is case-insentive. Should non-lowercase be an error?
546 let (parser, keyword) = assert_token parser Unset in
547 let (parser, left_paren, variables, right_paren) =
548 parse_parenthesized_comma_list_opt_allow_trailing parser parse_expression
550 let (parser, semi) = require_semicolon parser in
551 Make.unset_statement parser keyword left_paren variables right_paren semi
553 and parse_if_statement parser =
554 (* SPEC:
555 if-statement:
556 if ( expression ) statement elseif-clauses-opt else-clause-opt
557 if ( expression ): statement alt-elif-clauses-opt alt-else-clause-opt endif;
559 elseif-clauses:
560 elseif-clause
561 elseif-clauses elseif-clause
563 alt-elif-clauses:
564 alt-elif-clause
565 alt-elif-clauses alt-elif-clause
567 elseif-clause:
568 elseif ( expression ) statement
570 alt-elif-clause:
571 elseif ( expression ): statement
573 else-clause:
574 else statement
576 alt-else-clause:
577 else: statement
581 (* parses the "( expr ) statement" segment of If, Elseif or Else clauses.
582 * Return a tuple of 5 elements, the first one being the resultant parser
584 let parse_if_body_helper parser_body =
585 let (parser_body, left_paren_token, expr_node, right_paren_token) =
586 parse_paren_expr parser_body in
587 let parser1, opening_token = next_token parser_body in
588 let (parser1, opening_token_syntax) = Make.token parser1 opening_token in
589 let (parser_body, statement_node) = match Token.kind opening_token with
590 | Colon -> parse_alternate_if_block parser1 parse_statement
591 | _ -> parse_statement parser_body in
592 ( parser_body
593 , left_paren_token
594 , expr_node
595 , right_paren_token
596 , opening_token
597 , opening_token_syntax
598 , statement_node
601 let parse_elseif_opt parser_elseif =
602 if peek_token_kind parser_elseif = Elseif then
603 let (parser_elseif, elseif_token) = assert_token parser_elseif Elseif in
604 let ( parser_elseif
605 , elseif_left_paren
606 , elseif_condition_expr
607 , elseif_right_paren
608 , elseif_opening_token
609 , elseif_opening_token_syntax
610 , elseif_statement
612 parse_if_body_helper parser_elseif in
613 let (parser_elseif, elseif_syntax) = match Token.kind elseif_opening_token with
614 | Colon ->
615 Make.alternate_elseif_clause
616 parser_elseif
617 elseif_token
618 elseif_left_paren
619 elseif_condition_expr
620 elseif_right_paren
621 elseif_opening_token_syntax
622 elseif_statement
623 | _ ->
624 Make.elseif_clause
625 parser_elseif
626 elseif_token
627 elseif_left_paren
628 elseif_condition_expr
629 elseif_right_paren
630 elseif_statement
632 (parser_elseif, Some elseif_syntax)
633 else
634 (parser_elseif, None)
636 (* do not eat token and return Missing if first token is not Else *)
637 let parse_else_opt parser_else =
638 let (parser_else, else_token) = optional_token parser_else Else in
639 if SC.is_missing else_token then
640 (parser_else, else_token)
641 else
642 let parser1, opening_token = next_token parser_else in
643 match Token.kind opening_token with
644 | Colon ->
645 let (_parser, opening_token_syntax) =
646 Make.token parser opening_token
648 let (parser_else, else_consequence) =
649 parse_alternate_if_block parser1 parse_statement
651 Make.alternate_else_clause
652 parser_else
653 else_token
654 opening_token_syntax
655 else_consequence
656 | _ ->
657 let (parser_else, else_consequence) = parse_statement parser_else in
658 Make.else_clause parser_else else_token else_consequence
660 let (parser, if_keyword_token) = assert_token parser If in
661 let ( parser
662 , if_left_paren
663 , if_expr
664 , if_right_paren
665 , if_opening_token
666 , if_opening_token_syntax
667 , if_consequence
669 parse_if_body_helper parser in
670 let (parser, elseif_syntax) =
671 parse_list_until_none parser parse_elseif_opt in
672 let (parser, else_syntax) = parse_else_opt parser in
673 match Token.kind if_opening_token with
674 | Colon ->
675 let (parser, closing_token) =
676 require_token parser Endif (SyntaxError.error1059 Endif)
678 let (parser, semicolon_token) = require_semicolon parser in
679 Make.alternate_if_statement
680 parser
681 if_keyword_token
682 if_left_paren
683 if_expr
684 if_right_paren
685 if_opening_token_syntax
686 if_consequence
687 elseif_syntax
688 else_syntax
689 closing_token
690 semicolon_token
691 | _ ->
692 Make.if_statement
693 parser
694 if_keyword_token
695 if_left_paren
696 if_expr
697 if_right_paren
698 if_consequence
699 elseif_syntax
700 else_syntax
702 and parse_switch_statement parser =
703 (* SPEC:
705 The spec for switches is very simple:
707 switch-statement:
708 switch ( expression ) compound-statement
709 labeled-statement:
710 case-label
711 default-label
712 case-label:
713 case expression : statement
714 default-label:
715 default : statement
717 where the compound statement, if not empty, must consist of only labeled
718 statements.
720 These rules give a nice simple parse but it has some unfortunate properties.
721 Consider:
723 switch (foo)
725 case 1:
726 case 2:
727 break;
728 default:
729 break;
732 What's the parse of the compound statement contents based on that grammar?
734 case 1:
735 case 2:
736 break;
737 default:
738 break;
740 That is, the second case is a child of the first. That makes it harder
741 to write analyzers, it makes it harder to write pretty printers, and so on.
743 What do we really want here? We want a switch to be a collection of
744 *sections* where each section has one or more *labels* and zero or more
745 *statements*.
747 switch-statement:
748 switch ( expression ) { switch-sections-opt }
750 switch-sections:
751 switch-section
752 switch-sections switch-section
754 switch-section:
755 section-labels
756 section-statements-opt
757 section-fallthrough-opt
759 section-fallthrough:
760 fallthrough ;
762 section-labels:
763 section-label
764 section-labels section-label
766 section-statements:
767 statement
768 section-statements statement
770 The parsing of course has to be greedy; we never want to say that there
771 are zero statements *between* two sections.
773 TODO: Update the specification with these rules.
777 let (parser, switch_keyword_token) = assert_token parser Switch in
778 let (parser, left_paren_token, expr_node, right_paren_token) =
779 parse_paren_expr parser in
780 let (_, opening_token) = next_token parser in
781 let ((parser, opening_token_syntax), closing_token_kind) =
782 match Token.kind opening_token with
783 | Colon -> assert_token parser Colon, Endswitch
784 | _ -> require_left_brace parser, RightBrace in
785 let (parser, section_list) =
786 let (parser1, token) = next_token parser in
787 match Token.kind token with
788 | Semicolon when peek_token_kind parser1 = closing_token_kind ->
789 make_list parser1 []
790 | _ ->
791 parse_terminated_list parser parse_switch_section closing_token_kind
793 match closing_token_kind with
794 | Endswitch ->
795 let (parser, endswitch_token_syntax) =
796 require_token parser Endswitch (SyntaxError.error1059 Endswitch)
798 let (parser, semicolon) = require_semicolon parser in
799 Make.alternate_switch_statement
800 parser
801 switch_keyword_token
802 left_paren_token
803 expr_node
804 right_paren_token
805 opening_token_syntax
806 section_list
807 endswitch_token_syntax
808 semicolon
809 | _ ->
810 let (parser, right_brace_token) = require_right_brace parser in
811 Make.switch_statement
812 parser
813 switch_keyword_token
814 left_paren_token
815 expr_node
816 right_paren_token
817 opening_token_syntax
818 section_list
819 right_brace_token
821 and is_switch_fallthrough parser =
822 peek_token_kind parser = Fallthrough &&
823 peek_token_kind ~lookahead:1 parser = Semicolon
825 and parse_possible_erroneous_fallthrough parser =
826 if is_switch_fallthrough parser then
827 let parser = with_error parser SyntaxError.error1055
828 ~on_whole_token:true in
829 let (parser, result) = parse_switch_fallthrough parser in
830 (parser, result)
831 else
832 parse_expression_statement parser
834 and parse_switch_fallthrough parser =
835 (* We don't get here unless we have fallthrough ; *)
836 let (parser, keyword) = assert_token parser Fallthrough in
837 let (parser, semi) = assert_token parser Semicolon in
838 Make.switch_fallthrough parser keyword semi
840 and parse_switch_fallthrough_opt parser =
841 if is_switch_fallthrough parser then
842 parse_switch_fallthrough parser
843 else
845 * As long as we have FALLTHROUGH comments, insert a faux-statement as if
846 * there was a fallthrough statement. For example, the code
848 * > case 22:
849 * > $x = 0;
850 * > // FALLTHROUGH because we want all the other functionality as well
851 * > case 42:
852 * > foo($x);
853 * > break;
855 * Should be parsed as if it were
857 * > case 22:
858 * > $x = 0;
859 * > // FALLTHROUGH because we want all the other functionality as well
860 * > fallthrough;
861 * > case 43:
862 * > foo($x);
863 * > break;
865 * But since we have no actual occurrence (i.e. no position, no string) of
866 * that `fallthrough;` statement, we construct a `switch_fallthrough`, but
867 * fill it with `missing`.
869 let next = peek_token parser in
870 let commented_fallthrough =
871 List.exists
872 (fun t -> Trivia.kind t = TriviaKind.FallThrough)
873 (Token.leading next)
875 let (parser, missing) = Make.missing parser (pos parser) in
876 if commented_fallthrough
877 then
878 let (parser, missing1) = Make.missing parser (pos parser) in
879 Make.switch_fallthrough parser missing missing1
880 else
881 (parser, missing)
883 and parse_switch_section parser =
884 (* See parse_switch_statement for grammar *)
885 let (parser, labels) =
886 parse_list_until_none parser parse_switch_section_label
888 let parser =
889 if SC.is_missing labels then with_error parser SyntaxError.error2008
890 else parser
892 let (parser, statements) =
893 parse_list_until_none parser parse_switch_section_statement
895 let (parser, fallthrough) = parse_switch_fallthrough_opt parser in
896 Make.switch_section parser labels statements fallthrough
898 and parse_switch_section_statement parser =
899 if is_switch_fallthrough parser then (parser, None)
900 else match peek_token_kind parser with
901 | Default
902 | Case
903 | RightBrace
904 | Endswitch
905 | TokenKind.EndOfFile -> (parser, None)
906 | _ ->
907 let (parser, statement) = parse_statement parser in
908 (parser, Some statement)
910 and parse_switch_section_label parser =
911 (* See the grammar under parse_switch_statement *)
912 match peek_token_kind parser with
913 | Case ->
914 let (parser, label) = parse_case_label parser in
915 (parser, Some label)
916 | Default ->
917 let (parser, label) = parse_default_label parser in
918 (parser, Some label)
919 | _ -> (parser, None)
921 and parse_catch_clause_opt parser =
922 (* SPEC
923 catch ( type-specification-opt variable-name ) compound-statement
924 catch ( type-specification-opt name ) compound-statement [experimental-mode]
926 if peek_token_kind parser = Catch then
927 let (parser, catch_token) = assert_token parser Catch in
928 let (parser, left_paren) = require_left_paren parser in
929 let (parser, catch_type) =
930 match peek_token_kind parser with
931 | TokenKind.Variable ->
932 let parser = with_error parser SyntaxError.error1007 in
933 Make.missing parser (pos parser)
934 | _ -> parse_type_specifier parser
936 let (parser, catch_var) =
937 if Env.is_experimental_mode (env parser)
938 then require_name_or_variable parser
939 else require_variable parser
941 let (parser, right_paren) = require_right_paren parser in
942 let (parser, compound_stmt) = parse_compound_statement parser in
943 let (parser, catch_clause) =
944 Make.catch_clause
945 parser
946 catch_token
947 left_paren
948 catch_type
949 catch_var
950 right_paren
951 compound_stmt in
952 (parser, Some catch_clause)
953 else
954 (parser, None)
956 and parse_finally_clause_opt parser =
957 (* SPEC
958 finally-clause:
959 finally compound-statement
961 if peek_token_kind parser = Finally then
962 let (parser, finally_token) = assert_token parser Finally in
963 let (parser, compound_stmt) = parse_compound_statement parser in
964 Make.finally_clause parser finally_token compound_stmt
965 else
966 Make.missing parser (pos parser)
968 and parse_try_statement parser =
969 (* SPEC:
970 try-statement:
971 try compound-statement catch-clauses
972 try compound-statement finally-clause
973 try compound-statement catch-clauses finally-clause
975 let (parser, try_keyword_token) = assert_token parser Try in
976 let (parser, try_compound_stmt) = parse_compound_statement parser in
977 let (parser, catch_clauses) =
978 parse_list_until_none parser parse_catch_clause_opt
980 let (parser, finally_clause) = parse_finally_clause_opt parser in
981 (* If the catch and finally are both missing then we give an error in
982 a later pass. *)
983 Make.try_statement
984 parser
985 try_keyword_token
986 try_compound_stmt
987 catch_clauses
988 finally_clause
990 and parse_break_statement parser =
991 (* SPEC
992 break-statement:
993 break ;
995 However, PHP allows an optional expression; though Hack does not have
996 this feature, we allow it at parse time and produce an error later.
997 TODO: Implement that error. *)
999 (* We detect if we are not inside a switch or loop in a later pass. *)
1000 let (parser, break_token) = assert_token parser Break in
1001 let (parser, level) =
1002 if peek_token_kind parser = Semicolon then
1003 Make.missing parser (pos parser)
1004 else parse_expression parser in
1005 let (parser, semi_token) = require_semicolon parser in
1006 Make.break_statement parser break_token level semi_token
1008 and parse_continue_statement parser =
1009 (* SPEC
1010 continue-statement:
1011 continue ;
1013 However, PHP allows an optional expression; though Hack does not have
1014 this feature, we allow it at parse time and produce an error later.
1015 TODO: Implement that error. *)
1017 (* We detect if we are not inside a loop in a later pass. *)
1018 let (parser, continue_token) = assert_token parser Continue in
1019 let (parser, level) =
1020 if peek_token_kind parser = Semicolon then
1021 Make.missing parser (pos parser)
1022 else parse_expression parser in
1023 let (parser, semi_token) = require_semicolon parser in
1024 Make.continue_statement parser continue_token level semi_token
1026 and parse_return_statement parser =
1027 let (parser, return_token) = assert_token parser Return in
1028 let (parser1, semi_token) = next_token parser in
1029 if Token.kind semi_token = Semicolon then
1030 let (parser, missing) = Make.missing parser1 (pos parser) in
1031 let (parser, semi_token) = Make.token parser semi_token in
1032 Make.return_statement parser return_token missing semi_token
1033 else
1034 let (parser, expr) = parse_expression parser in
1035 let (parser, semi_token) = require_semicolon parser in
1036 Make.return_statement parser return_token expr semi_token
1038 and parse_goto_label parser =
1039 let parser, goto_label_name = next_token_non_reserved_as_name parser in
1040 let (parser, goto_label_name) = Make.token parser goto_label_name in
1041 let parser, colon = require_colon parser in
1042 Make.goto_label parser goto_label_name colon
1044 and parse_goto_statement parser =
1045 let parser, goto = assert_token parser Goto in
1046 let parser, goto_label_name = next_token_non_reserved_as_name parser in
1047 let (parser, goto_label_name) = Make.token parser goto_label_name in
1048 let parser, semicolon = require_semicolon parser in
1049 Make.goto_statement parser goto goto_label_name semicolon
1051 and parse_throw_statement parser =
1052 let (parser, throw_token) = assert_token parser Throw in
1053 let (parser, expr) = parse_expression parser in
1054 let (parser, semi_token) = require_semicolon parser in
1055 Make.throw_statement parser throw_token expr semi_token
1057 and parse_default_label parser =
1059 See comments under parse_switch_statement for the grammar.
1060 TODO: Update the spec.
1061 TODO: The spec is wrong; it implies that a statement must always follow
1062 the default:, but in fact
1063 switch($x) { default: }
1064 is legal. Fix the spec.
1065 TODO: PHP allows a default to end in a semi; Hack does not. We allow a semi
1066 here; add an error in a later pass.
1068 let (parser, default_token) = assert_token parser Default in
1069 let (parser, colon_token) =
1070 let (parser1, token) = next_token parser in
1071 if (Token.kind token) = Semicolon then
1072 Make.token parser1 token
1073 else
1074 require_colon parser
1076 Make.default_label parser default_token colon_token
1078 and parse_case_label parser =
1079 (* SPEC:
1080 See comments under parse_switch_statement for the grammar.
1081 TODO: The spec is wrong; it implies that a statement must always follow
1082 the case, but in fact
1083 switch($x) { case 10: }
1084 is legal. Fix the spec.
1085 TODO: PHP allows a case to end in a semi; Hack does not. We allow a semi
1086 here; add an error in a later pass.
1089 let (parser, case_token) = assert_token parser Case in
1090 let (parser, expr) = parse_expression parser in
1091 let (parser, colon_token) =
1092 let (parser1, token) = next_token parser in
1093 if (Token.kind token) = Semicolon then
1094 Make.token parser1 token
1095 else
1096 require_colon parser
1098 Make.case_label parser case_token expr colon_token
1100 and parse_global_statement_or_expression_statement parser =
1101 (* PHP has a statement of the form
1102 global comma-separated-variable-list ;
1103 This is not supported in Hack, but we parse it anyways so as to give
1104 a good error message. However we do not want to disallow legal statements
1105 like "global(123);" so we use a heuristic to see if this is a likely
1106 global statement. If not, we parse it as an expression statement.
1107 TODO: Add an error in a later pass if this statement is found in a
1108 Hack file.
1110 let (parser1, keyword) = assert_token parser Global in
1111 let is_global_statement =
1112 match peek_token_kind parser1 with
1113 | TokenKind.Variable | TokenKind.Dollar -> true
1114 | _ -> false
1116 if is_global_statement then
1117 let parse_simple_variable parser =
1118 with_expr_parser parser ExpressionParser.parse_simple_variable
1120 let (parser, variables) = parse_comma_list
1121 parser1 Semicolon SyntaxError.error1008 parse_simple_variable
1123 let (parser, semicolon) = require_semicolon parser in
1124 Make.global_statement parser keyword variables semicolon
1125 else
1126 parse_expression_statement parser
1128 and parse_function_static_declaration_or_expression_statement parser =
1129 (* Determine if the current token is a late-bound static scope to be
1130 * resolved by the '::' operator. (E.g., "static::foo".)
1132 if Token.kind (peek_token ~lookahead:1 parser) == TokenKind.ColonColon then
1133 parse_expression_statement parser
1134 else
1135 parse_function_static_declaration parser
1137 and parse_function_static_declaration parser =
1138 (* SPEC
1140 function-static-declaration:
1141 static static-declarator-list ;
1143 static-declarator-list:
1144 static-declarator
1145 static-declarator-list , static-declarator
1148 let (parser, static) = assert_token parser Static in
1149 let (parser, decls) = parse_comma_list
1150 parser Semicolon SyntaxError.error1008 parse_static_declarator in
1151 let (parser, semicolon) = require_semicolon parser in
1152 Make.function_static_statement parser static decls semicolon
1154 and parse_static_declarator parser =
1155 (* SPEC
1156 static-declarator:
1157 variable-name function-static-initializer-opt
1159 (* TODO: ERROR RECOVERY not very sophisticated here *)
1160 let (parser, variable_name) = require_variable parser in
1161 let (parser, init) = parse_static_initializer_opt parser in
1162 Make.static_declarator parser variable_name init
1164 and parse_static_initializer_opt parser =
1165 (* SPEC
1166 function-static-initializer:
1167 = const-expression
1169 let (parser1, token) = next_token parser in
1170 match (Token.kind token) with
1171 | Equal ->
1172 (* TODO: Detect if expression is not const *)
1173 let (parser, equal) = Make.token parser1 token in
1174 let (parser, value) = parse_expression parser in
1175 Make.simple_initializer parser equal value
1176 | _ -> Make.missing parser (pos parser)
1178 (* SPEC:
1179 TODO: update the spec to reflect that echo and print must be a statement
1180 echo-intrinsic:
1181 echo expression
1182 echo ( expression )
1183 echo expression-list-two-or-more
1185 expression-list-two-or-more:
1186 expression , expression
1187 expression-list-two-or-more , expression
1189 and parse_echo_statement parser =
1190 let parser, token = assert_token parser Echo in
1191 let parser, expression_list = parse_comma_list
1192 parser Semicolon SyntaxError.error1015 parse_expression
1194 let parser, semicolon = require_semicolon parser in
1195 Make.echo_statement parser token expression_list semicolon
1197 and parse_expression_statement parser =
1198 let (parser1, token) = next_token parser in
1199 match Token.kind token with
1200 | Semicolon ->
1201 let (parser, missing) = Make.missing parser1 (pos parser) in
1202 let (parser, token) = Make.token parser token in
1203 Make.expression_statement parser missing token
1204 | _ ->
1205 let parser = Parser.expect_in_new_scope parser [ Semicolon ] in
1206 let (parser, expression) = parse_expression parser in
1207 let (parser, token) =
1208 let (parser, token) = require_semicolon_token parser in
1209 match token with
1210 | Some t ->
1211 if SC.is_halt_compiler_expression expression then
1212 let (parser, token) = rescan_halt_compiler parser t in
1213 Make.token parser token
1214 else
1215 Make.token parser t
1216 | None ->
1217 Make.missing parser (pos parser)
1219 let parser = Parser.pop_scope parser [ Semicolon ] in
1220 Make.expression_statement parser expression token
1222 and parse_compound_statement parser =
1223 let (parser1, token) = next_token parser in
1224 match Token.kind token with
1225 | Semicolon -> Make.token parser1 token
1226 | _ ->
1227 let (parser, left_brace_token) = require_left_brace parser in
1228 let (parser, statement_list) =
1229 parse_terminated_list parser parse_statement RightBrace
1231 let (parser, right_brace_token) = require_right_brace parser in
1232 Make.compound_statement parser left_brace_token statement_list
1233 right_brace_token
1235 and parse_alternate_loop_statement parser ~terminator =
1236 let (parser, colon_token) = assert_token parser Colon in
1237 let (parser, statement_list) =
1238 parse_terminated_list parser parse_statement terminator in
1239 let (parser, terminate_token) = require_token parser terminator
1240 (SyntaxError.error1059 terminator) in
1241 let (parser, semicolon_token) = require_semicolon parser in
1242 Make.alternate_loop_statement
1243 parser
1244 colon_token
1245 statement_list
1246 terminate_token
1247 semicolon_token
1250 end (* WithSmartConstructors *)
1251 end (* WithSyntax *)