Generate SyntaxKindWrapper for smart constructors
[hiphop-php.git] / hphp / hack / src / parser / full_fidelity_expression_parser.ml
blob70a789d6b881a76e56b4e9e48943be0ef12c8926
1 (**
2 * Copyright (c) 2016, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the "hack" directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
9 *)
11 module WithSyntax(Syntax : Syntax_sig.Syntax_S) = struct
13 module Token = Syntax.Token
14 module SyntaxKind = Full_fidelity_syntax_kind
15 module TokenKind = Full_fidelity_token_kind
16 module SourceText = Full_fidelity_source_text
17 module SyntaxError = Full_fidelity_syntax_error
18 module Operator = Full_fidelity_operator
19 module Lexer = Full_fidelity_lexer.WithToken(Syntax.Token)
20 module Env = Full_fidelity_parser_env
21 module PrecedenceSyntax = Full_fidelity_precedence_parser
22 .WithSyntax(Syntax)
23 module PrecedenceParser = PrecedenceSyntax
24 .WithLexer(Full_fidelity_lexer.WithToken(Syntax.Token))
25 module type SCWithKind_S = SmartConstructorsWrappers.SyntaxKind_S
27 module type StatementParser_S = Full_fidelity_statement_parser_type
28 .WithSyntax(Syntax)
29 .WithLexer(Full_fidelity_lexer.WithToken(Syntax.Token))
30 .StatementParser_S
32 module type DeclarationParser_S = Full_fidelity_declaration_parser_type
33 .WithSyntax(Syntax)
34 .WithLexer(Full_fidelity_lexer.WithToken(Syntax.Token))
35 .DeclarationParser_S
37 module type TypeParser_S = Full_fidelity_type_parser_type
38 .WithSyntax(Syntax)
39 .WithLexer(Full_fidelity_lexer.WithToken(Syntax.Token))
40 .TypeParser_S
42 module type ExpressionParser_S = Full_fidelity_expression_parser_type
43 .WithSyntax(Syntax)
44 .WithLexer(Full_fidelity_lexer.WithToken(Syntax.Token))
45 .ExpressionParser_S
47 module ParserHelperSyntax = Full_fidelity_parser_helpers.WithSyntax(Syntax)
48 module ParserHelper =
49 ParserHelperSyntax.WithLexer(Full_fidelity_lexer.WithToken(Syntax.Token))
51 module WithSmartConstructors (SCI : SCWithKind_S with type token = Token.t)
52 = struct
54 module WithStatementAndDeclAndTypeParser
55 (StatementParser : StatementParser_S with module SC = SCI)
56 (DeclParser : DeclarationParser_S with module SC = SCI)
57 (TypeParser : TypeParser_S with module SC = SCI)
58 : (ExpressionParser_S with module SC = SCI)
59 = struct
61 open TokenKind
62 open Syntax
64 module Parser = PrecedenceParser.WithSmartConstructors(SCI)
65 include Parser
66 include ParserHelper.WithParser(Parser)
68 type binary_expression_prefix_kind =
69 | Prefix_byref_assignment | Prefix_assignment | Prefix_none
71 let make_and_track_prefix_unary_expression parser operator kind operand =
72 let node = make_prefix_unary_expression operator operand in
73 let prefix_unary_expression_stack =
74 {node; operator_kind = kind; operand} ::
75 parser.prefix_unary_expression_stack
77 {parser with prefix_unary_expression_stack}, node
79 let find_in_prefix_unary_expression_stack parser node =
80 List.find_opt (fun {node = n; _} -> n == node)
81 parser.prefix_unary_expression_stack
83 (* [Trick] *)
85 let with_type_parser : 'a . t -> (TypeParser.t -> TypeParser.t * 'a) -> t * 'a
86 = fun parser f ->
87 let type_parser =
88 TypeParser.make
89 parser.env
90 parser.lexer
91 parser.errors
92 parser.context
93 parser.sc_state
95 let (type_parser, node) = f type_parser in
96 let env = TypeParser.env type_parser in
97 let lexer = TypeParser.lexer type_parser in
98 let errors = TypeParser.errors type_parser in
99 let context = TypeParser.context type_parser in
100 let sc_state = TypeParser.sc_state type_parser in
101 let parser = { parser with env; lexer; errors; context; sc_state } in
102 (parser, node)
104 let parse_generic_type_arguments_opt parser =
105 with_type_parser parser TypeParser.parse_generic_type_argument_list_opt
107 let with_decl_parser : 'a . t -> (DeclParser.t -> DeclParser.t * 'a) -> t * 'a
108 = fun parser f ->
109 let decl_parser =
110 DeclParser.make
111 parser.env
112 parser.lexer
113 parser.errors
114 parser.context
115 parser.sc_state
117 let (decl_parser, node) = f decl_parser in
118 let env = DeclParser.env decl_parser in
119 let lexer = DeclParser.lexer decl_parser in
120 let errors = DeclParser.errors decl_parser in
121 let context = DeclParser.context decl_parser in
122 let sc_state = DeclParser.sc_state decl_parser in
123 let parser = { parser with env; lexer; errors; context; sc_state } in
124 (parser, node)
126 let parse_compound_statement parser =
127 let statement_parser =
128 StatementParser.make
129 parser.env
130 parser.lexer
131 parser.errors
132 parser.context
133 parser.sc_state
135 let (statement_parser, statement) =
136 StatementParser.parse_compound_statement statement_parser in
137 let env = StatementParser.env statement_parser in
138 let lexer = StatementParser.lexer statement_parser in
139 let errors = StatementParser.errors statement_parser in
140 let context = StatementParser.context statement_parser in
141 let sc_state = StatementParser.sc_state statement_parser in
142 let parser = { parser with env; lexer; errors; context; sc_state } in
143 (parser, statement)
145 let is_valid_type_argument_list type_arguments parser0 parser1 =
146 kind type_arguments = SyntaxKind.TypeArguments
147 && List.for_all (fun c -> not (is_missing c)) (children type_arguments)
148 && parser0.errors = parser1.errors
150 let parse_parameter_list_opt parser =
151 let (parser, (left, token, right)) = with_decl_parser parser
152 (fun decl_parser ->
153 let (parser, left, token, right) =
154 DeclParser.parse_parameter_list_opt decl_parser
156 parser, (left, token, right)
159 (parser, left, token, right)
161 let rec parse_expression parser =
162 let (parser, term) = parse_term parser in
163 parse_remaining_expression parser term
165 and parse_expression_with_reset_precedence parser =
166 with_reset_precedence parser parse_expression
168 and parse_expression_with_operator_precedence parser operator =
169 with_operator_precedence parser operator parse_expression
171 and parse_if_no_error parser f =
172 let old_errors = List.length (errors parser) in
174 let (parser, result) = f parser in
175 let new_errors = List.length(errors parser) in
176 Option.some_if (old_errors = new_errors) (parser, result)
177 with Failure _ -> None
179 and parse_as_name_or_error parser =
180 (* TODO: Are there "reserved" keywords that absolutely cannot start
181 an expression? If so, list them above and make them produce an
182 error. *)
183 let (parser1, token) = next_token_as_name parser in
184 match (Token.kind token) with
185 | Name ->
186 let (parser1, name) =
187 scan_remaining_qualified_name parser1 (make_token token) in
188 parse_name_or_collection_literal_expression parser1 name
189 | kind when Parser.expects_here parser kind ->
190 (* ERROR RECOVERY: If we're encountering a token that matches a kind in
191 * the previous scope of the expected stack, don't eat it--just mark the
192 * name missing and continue parsing, starting from the offending token. *)
193 let missing = make_missing parser in
194 let parser = with_error parser SyntaxError.error1015 in
195 (parser, missing)
196 | _ ->
197 (* ERROR RECOVERY: If we're encountering anything other than a Name
198 * or the next expected kind, eat the offending token.
199 * TODO: Increase the coverage of PrecedenceParser.expects_next, so that
200 * we wind up eating fewer of the tokens that'll be needed by the outer
201 * statement / declaration parsers. *)
202 let parser = with_error parser1 SyntaxError.error1015 in
203 (parser, make_token token)
205 and parse_term parser =
206 let (parser1, token) = next_xhp_class_name_or_other_token parser in
207 match (Token.kind token) with
208 (* TODO: Make these an error in Hack *)
209 | ExecutionStringLiteral
210 | DecimalLiteral
211 | OctalLiteral
212 | HexadecimalLiteral
213 | BinaryLiteral
214 | FloatingLiteral
215 | SingleQuotedStringLiteral
216 | NowdocStringLiteral
217 | DoubleQuotedStringLiteral
218 | BooleanLiteral
219 | NullLiteral -> (parser1, make_literal_expression (make_token token))
220 | HeredocStringLiteral ->
221 (* We have a heredoc string literal but it might contain embedded
222 expressions. Start over. *)
223 let (parser, token, name) = next_docstring_header parser in
224 parse_heredoc_string parser (make_token token) name
225 | HeredocStringLiteralHead
226 | DoubleQuotedStringLiteralHead ->
227 parse_double_quoted_like_string
228 parser1 (make_token token) Lexer.Literal_double_quoted
229 | ExecutionStringLiteralHead ->
230 parse_double_quoted_like_string
231 parser1 (make_token token) Lexer.Literal_execution_string
232 | Variable -> parse_variable_or_lambda parser
233 | XHPClassName ->
234 parse_name_or_collection_literal_expression parser1 (make_token token)
235 | Name ->
236 let (parser1, qualified_name) =
237 scan_remaining_qualified_name parser1 (make_token token) in
238 parse_name_or_collection_literal_expression parser1 qualified_name
239 | Backslash ->
240 let (parser1, qualified_name) =
241 scan_qualified_name parser1 (make_token token) in
242 parse_name_or_collection_literal_expression parser1 qualified_name
243 | Self
244 | Parent -> parse_scope_resolution_or_name parser
245 | Static ->
246 parse_anon_or_awaitable_or_scope_resolution_or_name parser
247 | Yield -> parse_yield_expression parser
248 | Dollar -> parse_dollar_expression parser
249 | Suspend
250 (* TODO: The operand to a suspend is required to be a call to a
251 coroutine. Give an error in a later pass if this isn't the case. *)
252 | Exclamation
253 | PlusPlus
254 | MinusMinus
255 | Tilde
256 | Minus
257 | Plus
258 | Ampersand
259 | Await
260 | Clone
261 | Print
262 | At -> parse_prefix_unary_expression parser
263 | LeftParen -> parse_cast_or_parenthesized_or_lambda_expression parser
264 | LessThan -> parse_possible_xhp_expression ~consume_trailing_trivia:true parser
265 | List -> parse_list_expression parser
266 | New -> parse_object_creation_expression parser
267 | Array -> parse_array_intrinsic_expression parser
268 | Varray -> parse_varray_intrinsic_expression parser
269 | Vec -> parse_vector_intrinsic_expression parser
270 | Darray -> parse_darray_intrinsic_expression parser
271 | Dict -> parse_dictionary_intrinsic_expression parser
272 | Keyset -> parse_keyset_intrinsic_expression parser
273 | LeftBracket -> parse_array_creation_expression parser
274 | Tuple -> parse_tuple_expression parser
275 | Shape -> parse_shape_expression parser
276 | Function -> parse_anon parser
277 | DollarDollar ->
278 (parser1, make_pipe_variable_expression (make_token token))
279 | Async
280 | Coroutine -> parse_anon_or_lambda_or_awaitable parser
281 | Include
282 | Include_once
283 | Require
284 | Require_once -> parse_inclusion_expression parser
285 | Empty -> parse_empty_expression parser
286 | Isset -> parse_isset_expression parser
287 | Define -> parse_define_expression parser
288 | HaltCompiler -> parse_halt_compiler_expression parser
289 | Eval -> parse_eval_expression parser
290 | kind when Parser.expects parser kind ->
291 (* ERROR RECOVERY: if we've prematurely found a token we're expecting
292 * later, mark the expression missing, throw an error, and do not advance
293 * the parser. *)
294 let missing = make_missing parser in
295 let parser = with_error parser SyntaxError.error1015 in
296 (parser, missing)
297 | TokenKind.EndOfFile
298 | _ -> parse_as_name_or_error parser
300 and parse_empty_expression parser =
301 (* TODO: This is a PHP-ism. Open questions:
302 * Should we allow a trailing comma? it is not a function call and
303 never has more than one argument. See D4273242 for discussion.
304 * Is there any restriction on the kind of expression this can be?
305 * Should this be an error in strict mode?
306 * Should this be in the specification?
307 * Empty is case-insensitive; should use of non-lowercase be an error?
309 (* TODO: The original Hack and HHVM parsers accept "empty" as an
310 identifier, so we do too; consider whether it should be reserved. *)
311 let (parser1, keyword) = assert_token parser Empty in
312 if peek_token_kind parser1 = LeftParen then
313 let (parser, left) = assert_token parser1 LeftParen in
314 let (parser, arg) = parse_expression_with_reset_precedence parser in
315 let (parser, right) = require_right_paren parser in
316 let result = make_empty_expression keyword left arg right in
317 (parser, result)
318 else
319 parse_as_name_or_error parser
321 and parse_eval_expression parser =
322 (* TODO: This is a PHP-ism. Open questions:
323 * Should we allow a trailing comma? it is not a function call and
324 never has more than one argument. See D4273242 for discussion.
325 * Is there any restriction on the kind of expression this can be?
326 * Should this be an error in strict mode?
327 * Should this be in the specification?
328 * Eval is case-insensitive. Should use of non-lowercase be an error?
330 (* TODO: The original Hack and HHVM parsers accept "eval" as an
331 identifier, so we do too; consider whether it should be reserved. *)
332 let (parser1, keyword) = assert_token parser Eval in
333 if peek_token_kind parser1 = LeftParen then
334 let (parser, left) = assert_token parser1 LeftParen in
335 let (parser, arg) = parse_expression_with_reset_precedence parser in
336 let (parser, right) = require_right_paren parser in
337 let result = make_eval_expression keyword left arg right in
338 (parser, result)
339 else
340 parse_as_name_or_error parser
342 and parse_isset_expression parser =
343 (* TODO: This is a PHP-ism. Open questions:
344 * Should we allow a trailing comma? See D4273242 for discussion.
345 * Is there any restriction on the kind of expression the arguments can be?
346 * Should this be an error in strict mode?
347 * Should this be in the specification?
348 * PHP requires that there be at least one argument; should we require
349 that? if so, should we give the error in the parser or a later pass?
350 * Isset is case-insensitive. Should use of non-lowercase be an error?
352 (* TODO: The original Hack and HHVM parsers accept "isset" as an
353 identifier, so we do too; consider whether it should be reserved. *)
355 let (parser1, keyword) = assert_token parser Isset in
356 if peek_token_kind parser1 = LeftParen then
357 let (parser, left, args, right) = parse_expression_list_opt parser1 in
358 let result = make_isset_expression keyword left args right in
359 (parser, result)
360 else
361 parse_as_name_or_error parser
363 and parse_define_expression parser =
364 (* TODO: This is a PHP-ism. Open questions:
365 * Should we allow a trailing comma? See D4273242 for discussion.
366 * Is there any restriction on the kind of expression the arguments can be?
367 They must be string, value, bool, but do they have to be compile-time
368 constants, for instance?
369 * Should this be an error in strict mode? You should use const instead.
370 * Should this be in the specification?
371 * PHP requires that there be at least two arguments; should we require
372 that? if so, should we give the error in the parser or a later pass?
373 * is define case-insensitive?
375 (* TODO: The original Hack and HHVM parsers accept "define" as an
376 identifier, so we do too; consider whether it should be reserved. *)
377 let (parser1, keyword) = assert_token parser Define in
378 if peek_token_kind parser1 = LeftParen then
379 let (parser, left, args, right) = parse_expression_list_opt parser1 in
380 let result = make_define_expression keyword left args right in
381 (parser, result)
382 else
383 parse_as_name_or_error parser
385 and parse_halt_compiler_expression parser =
386 let (parser1, keyword) = assert_token parser HaltCompiler in
387 if peek_token_kind parser1 = LeftParen then
388 let (parser, left, args, right) = parse_expression_list_opt parser1 in
389 parser, make_halt_compiler_expression keyword left args right
390 else
391 let parser = with_error parser SyntaxError.error1019 in
392 parse_as_name_or_error parser
394 and parse_double_quoted_like_string parser head literal_kind =
395 parse_string_literal parser head literal_kind
397 and parse_heredoc_string parser head name =
398 parse_string_literal parser head (Lexer.Literal_heredoc name)
400 and parse_braced_expression_in_string parser =
402 We are parsing something like "abc{$x}def" or "abc${x}def", and we
403 are at the left brace.
405 We know that the left brace will not be preceded by trivia. However in the
406 second of the two cases mentioned above it is legal for there to be trivia
407 following the left brace. If we are in the first case, we've already
408 verified that there is no trailing trivia after the left brace.
410 The expression may be followed by arbitrary trivia, including
411 newlines and comments. That means that the closing brace may have
412 leading trivia. But under no circumstances does the closing brace have
413 trailing trivia.
415 It's an error for the closing brace to be missing.
417 Therefore we lex the left brace normally, parse the expression normally,
418 but require that there be a right brace. We do not lex the trailing trivia
419 on the right brace.
421 ERROR RECOVERY: If the right brace is missing, treat the remainder as
422 string text. *)
424 let (parser, left_brace) = assert_token parser LeftBrace in
425 let (parser1, name_or_keyword_as_name) = next_token_as_name parser in
426 let (parser1, right_brace) = next_token_no_trailing parser1 in
427 let (parser, expr, right_brace) =
428 match Token.kind name_or_keyword_as_name, Token.kind right_brace with
429 | Name, RightBrace ->
430 let expr = make_token name_or_keyword_as_name in
431 let right_brace = make_token right_brace in
432 parser1, expr, right_brace
433 | _, _ ->
434 let (parser, expr) = parse_expression_with_reset_precedence parser in
435 let (parser1, token) = next_token_no_trailing parser in
436 let (parser, right_brace) =
437 if (Token.kind token) = RightBrace then
438 (parser1, make_token token)
439 else
440 let missing = make_missing parser in
441 let parser = with_error parser SyntaxError.error1006 in
442 (parser, missing)
444 parser, expr, right_brace
446 let node = make_embedded_braced_expression left_brace expr right_brace in
447 (parser, node)
449 and parse_string_literal parser head literal_kind =
450 (* SPEC
452 Double-quoted string literals and heredoc string literals use basically
453 the same rules; here we have just the grammar for double-quoted string
454 literals.
456 string-variable::
457 variable-name offset-or-property-opt
459 offset-or-property::
460 offset-in-string
461 property-in-string
463 offset-in-string::
464 [ name ]
465 [ variable-name ]
466 [ integer-literal ]
468 property-in-string::
469 -> name
471 TODO: What about ?->
473 The actual situation is considerably more complex than indicated
474 in the specification.
476 TODO: Consider updating the specification.
478 * The tokens in the grammar above have no leading or trailing trivia.
480 * An embedded variable expression may also be enclosed in curly braces;
481 however, the $ of the variable expression must follow immediately after
482 the left brace.
484 * An embedded variable expression inside braces allows trivia between
485 the tokens and before the right brace.
487 * An embedded variable expression inside braces can be a much more complex
488 expression than indicated by the grammar above. For example,
489 {$c->x->y[0]} is good, and {$c[$x instanceof foo ? 0 : 1]} is good,
490 but {$c instanceof foo ? $x : $y} is not. It is not clear to me what
491 the legal grammar here is; it seems best in this situation to simply
492 parse any expression and do an error pass later.
494 * Note that the braced expressions can include double-quoted strings.
495 {$c["abc"]} is good, for instance.
497 * ${ is illegal in strict mode. In non-strict mode, ${varname is treated
498 the same as {$varname, and may be an arbitrary expression.
500 * TODO: We need to produce errors if there are unbalanced brackets,
501 example: "$x[0" is illegal.
503 * TODO: Similarly for any non-valid thing following the left bracket,
504 including trivia. example: "$x[ 0]" is illegal.
508 let merge token head =
509 (* TODO: Assert that new head has no leading trivia, old head has no
510 trailing trivia. *)
511 (* Invariant: A token inside a list of string fragments is always a head,
512 body or tail. *)
513 (* TODO: Is this invariant what we want? We could preserve the parse of
514 the string. That is, something like "a${b}c${d}e" is at present
515 represented as head, expr, body, expr, tail. It could be instead
516 head, dollar, left brace, expr, right brace, body, dollar, left
517 brace, expr, right brace, tail. Is that better?
519 TODO: Similarly we might want to preserve the structure of
520 heredoc strings in the parse: that there is a header consisting of
521 an identifier, and so on, and then body text, etc. *)
522 let k = match (Token.kind head, Token.kind token) with
523 | (DoubleQuotedStringLiteralHead, DoubleQuotedStringLiteralTail) ->
524 DoubleQuotedStringLiteral
525 | (ExecutionStringLiteralHead, ExecutionStringLiteralTail) ->
526 ExecutionStringLiteral
527 | (HeredocStringLiteralHead, HeredocStringLiteralTail) ->
528 HeredocStringLiteral
529 | (DoubleQuotedStringLiteralHead, _) -> DoubleQuotedStringLiteralHead
530 | (ExecutionStringLiteralHead, _) -> ExecutionStringLiteralHead
531 | (HeredocStringLiteralHead, _) -> HeredocStringLiteralHead
532 | (_, DoubleQuotedStringLiteralTail) -> DoubleQuotedStringLiteralTail
533 | (_, HeredocStringLiteralTail) -> HeredocStringLiteralTail
534 | (_, ExecutionStringLiteralTail) -> ExecutionStringLiteralTail
535 | _ -> StringLiteralBody in
536 let s = Token.source_text head in
537 let o = Token.leading_start_offset head in
538 let w = (Token.width head) + (Token.width token) in
539 let l = Token.leading head in
540 let t = Token.trailing token in
541 (* TODO: Make a "position" type that is a tuple of source and offset. *)
542 let result = Token.make k s o w l t in
543 make_token result in
545 let merge_head token acc =
546 match acc with
547 | h :: t ->
548 begin
549 match Syntax.get_token h with
550 | None ->
551 let k = Token.kind token in
552 let token = match k with
553 | StringLiteralBody
554 | HeredocStringLiteralTail
555 | DoubleQuotedStringLiteralTail
556 | ExecutionStringLiteralTail -> token
557 | _ -> Token.with_kind token StringLiteralBody in
558 (make_token token) :: acc
559 | Some head -> (merge token head) :: t
561 | _ -> (make_token token) :: acc in
563 let parse_embedded_expression parser token =
564 let var_expr = make_variable_expression (make_token token) in
565 let (parser1, token1) = next_token_in_string parser literal_kind in
566 let (parser2, token2) = next_token_in_string parser1 literal_kind in
567 let (parser3, token3) = next_token_in_string parser2 literal_kind in
568 match (Token.kind token1, Token.kind token2, Token.kind token3) with
569 | (MinusGreaterThan, Name, _) ->
570 let expr = make_embedded_member_selection_expression var_expr
571 (make_token token1) (make_token token2) in
572 (parser2, expr)
573 | (LeftBracket, Name, RightBracket) ->
574 let expr = make_embedded_subscript_expression var_expr
575 (make_token token1)
576 (make_token token2)
577 (make_token token3) in
578 (parser3, expr)
579 | (LeftBracket, Variable, RightBracket) ->
580 let expr = make_embedded_subscript_expression var_expr
581 (make_token token1) (make_variable_expression (make_token token2))
582 (make_token token3) in
583 (parser3, expr)
584 | (LeftBracket, DecimalLiteral, RightBracket)
585 | (LeftBracket, OctalLiteral, RightBracket)
586 | (LeftBracket, HexadecimalLiteral, RightBracket)
587 | (LeftBracket, BinaryLiteral, RightBracket) ->
588 let expr = make_embedded_subscript_expression var_expr
589 (make_token token1) (make_literal_expression (make_token token2))
590 (make_token token3) in
591 (parser3, expr)
592 | _ -> (parser, var_expr) in
594 let rec handle_left_brace parser acc =
595 (* Note that here we use next_token_in_string because we need to know
596 whether there is trivia between the left brace and the $x which follows.*)
597 let (parser1, left_brace) = next_token_in_string parser literal_kind in
598 let (_, token) = next_token_in_string parser1 literal_kind in
599 (* TODO: What about "{$$}" ? *)
600 match Token.kind token with
601 | Dollar ->
602 (* We do not support {$ inside a string unless the $ begins a
603 variable name. Append the { and start again on the $. *)
604 (* TODO: Is this right? Suppose we have "{${x}". Is that the same
605 as "{"."${x}" ? Double check this. *)
606 (* TODO: Give an error. *)
607 aux parser1 (merge_head left_brace acc)
608 | Variable ->
609 (* Parse any expression followed by a close brace.
610 TODO: We do not actually support all possible expressions;
611 see above. Do we want to (1) catch this at parse time,
612 (2) catch it in a later pass, or (3) just allow any
613 expression here? *)
614 let (parser, expr) = parse_braced_expression_in_string parser in
615 aux parser (expr :: acc)
616 | _ ->
617 (* We got a { not followed by a $. Ignore it. *)
618 (* TODO: Give a warning? *)
619 aux parser1 (merge_head left_brace acc)
621 and handle_dollar parser dollar acc =
622 (* We need to parse ${x} as though it was {$x} *)
623 (* TODO: This should be an error in strict mode. *)
624 (* We must not have trivia between the $ and the {, but we can have
625 trivia after the {. That's why we use next_token_in_string here. *)
626 let (_, token) = next_token_in_string parser literal_kind in
627 match Token.kind token with
628 | LeftBrace ->
629 (* The thing in the braces has to be an expression that begins
630 with a variable, and the variable does *not* begin with a $. It's
631 just the word.
633 Unlike the {$var} case, there *can* be trivia before the expression,
634 which means that trivia is likely the trailing trivia of the brace,
635 not leading trivia of the expression. *)
636 (* TODO: Enforce these rules by producing an error if they are
637 violated. *)
638 (* TODO: Make the parse tree for the leading word in the expression
639 a variable expression, not a qualified name expression. *)
641 let (parser, expr) = parse_braced_expression_in_string parser in
642 aux parser (expr :: (make_token dollar) :: acc)
644 | _ ->
645 (* We got a $ not followed by a { or variable name. Ignore it. *)
646 (* TODO: Give a warning? *)
647 aux parser (merge_head dollar acc)
649 and aux parser acc =
650 let (parser1, token) = next_token_in_string parser literal_kind in
651 match Token.kind token with
652 | HeredocStringLiteralTail
653 | DoubleQuotedStringLiteralTail
654 | ExecutionStringLiteralTail -> (parser1, (merge_head token acc))
655 | LeftBrace -> handle_left_brace parser acc
656 | Variable ->
657 let (parser, expr) = parse_embedded_expression parser1 token in
658 aux parser (expr :: acc)
659 | Dollar -> handle_dollar parser1 token acc
660 | _ -> aux parser1 (merge_head token acc) in
662 let (parser, results) = aux parser [head] in
663 (* If we've ended up with a single string literal with no internal
664 structure, do not represent that as a list with one item. *)
665 let results = match results with
666 | h :: [] -> h
667 | _ -> make_list parser (List.rev results) in
668 let result = make_literal_expression results in
669 (parser, result)
671 and parse_inclusion_expression parser =
672 (* SPEC:
673 inclusion-directive:
674 require-multiple-directive
675 require-once-directive
677 require-multiple-directive:
678 require include-filename ;
680 include-filename:
681 expression
683 require-once-directive:
684 require_once include-filename ;
686 In non-strict mode we allow an inclusion directive (without semi) to be
687 used as an expression. It is therefore easier to actually parse this as:
689 inclusion-directive:
690 inclusion-expression ;
692 inclusion-expression:
693 require include-filename
694 require_once include-filename
696 TODO: We allow "include" and "include_once" as well, which are PHP-isms
697 specified as not supported in Hack. Do we need to produce an error in
698 strict mode?
700 TODO: Produce an error if this is used in an expression context
701 in strict mode.
704 let (parser, require) = next_token parser in
705 let operator = Operator.prefix_unary_from_token (Token.kind require) in
706 let require = make_token require in
707 let (parser, filename) = parse_expression_with_operator_precedence
708 parser operator in
709 let result = make_inclusion_expression require filename in
710 (parser, result)
712 and peek_next_kind_if_operator parser =
713 let kind = peek_token_kind parser in
714 if Operator.is_trailing_operator_token kind then
715 Some kind
716 else
717 None
719 and operator_has_lower_precedence operator_kind parser =
720 let operator = Operator.trailing_from_token operator_kind in
721 (Operator.precedence operator) < parser.precedence
723 and next_is_lower_precedence parser =
724 match peek_next_kind_if_operator parser with
725 | None -> true
726 | Some kind -> operator_has_lower_precedence kind parser
728 and parse_remaining_expression_or_specified_function_call parser term
729 prefix_kind =
730 let parser1, type_arguments = parse_generic_type_arguments_opt parser in
731 if is_valid_type_argument_list type_arguments parser parser1
732 then
733 let parser, result =
734 begin match peek_token_kind parser1 with
735 | ColonColon ->
736 (* handle a<type-args>::... case *)
737 let type_specifier =
738 make_generic_type_specifier term type_arguments in
739 parse_scope_resolution_expression parser1 type_specifier
740 | _ ->
741 let (parser, left, args, right) = parse_expression_list_opt parser1 in
742 parser, make_function_call_with_type_arguments_expression
743 term type_arguments left args right
744 end in
745 parse_remaining_expression parser result
746 else
747 parse_remaining_binary_expression parser term prefix_kind
749 (* Checks if given expression is a PHP variable.
750 per PHP grammar:
751 https://github.com/php/php-langspec/blob/master/spec/10-expressions.md#grammar-variable
752 A variable is an expression that can in principle be used as an lvalue *)
753 and can_be_used_as_lvalue parser t =
754 if is_variable_expression t
755 || is_subscript_expression t
756 || is_member_selection_expression t
757 || is_scope_resolution_expression t
758 then true
759 else prefix_unary_expression_checker_helper parser t Dollar
761 (* Checks if given node is prefix unary expression and verifies operator kind.
762 Recursively run can_be_used_as_lvalue *)
763 and prefix_unary_expression_checker_helper parser t kind =
764 match find_in_prefix_unary_expression_stack parser t with
765 | Some { operator_kind; operand; _ } ->
766 if operator_kind = kind then
767 can_be_used_as_lvalue parser operand
768 else
769 false
770 | None -> false
772 (* checks if expression is a valid right hand side in by-ref assignment
773 which is '&'PHP variable *)
774 and is_byref_assignment_source parser t =
775 prefix_unary_expression_checker_helper parser t Ampersand
777 (*detects if left_term and operator can be treated as a beginning of
778 assignment (respecting the precedence of operator on the left of
779 left term). Returns
780 - Prefix_none - either operator is not one of assignment operators or
781 precedence of the operator on the left is higher than precedence of
782 assignment.
783 - Prefix_assignment - left_term and operator can be interpreted as a
784 prefix of assignment
785 - Prefix_byref_assignment - left_term and operator can be interpreted as a
786 prefix of byref assignment.*)
787 and check_if_parsable_as_assignment parser left_term operator left_precedence
789 (* in PHP precedence of assignment in expression is bumped up to
790 recognize cases like !$x = ... or $a == $b || $c = ...
791 which should be parsed as !($x = ...) and $a == $b || ($c = ...)
793 if left_precedence >= Operator.precedence_for_assignment_in_expressions then
794 Prefix_none
795 else match operator with
796 | Equal when can_be_used_as_lvalue parser left_term ->
797 Prefix_byref_assignment
798 | Equal when is_list_expression left_term -> Prefix_assignment
799 | PlusEqual | MinusEqual | StarEqual | SlashEqual |
800 StarStarEqual | DotEqual | PercentEqual | AmpersandEqual |
801 BarEqual | CaratEqual | LessThanLessThanEqual |
802 GreaterThanGreaterThanEqual
803 when can_be_used_as_lvalue parser left_term ->
804 Prefix_assignment
805 | _ -> Prefix_none
807 and can_term_take_type_args term =
808 match kind term with
809 | SyntaxKind.Token -> is_name term
810 | SyntaxKind.QualifiedName
811 | SyntaxKind.MemberSelectionExpression
812 | SyntaxKind.SafeMemberSelectionExpression
813 | SyntaxKind.ScopeResolutionExpression -> true
814 | _ -> false
816 and parse_remaining_expression parser term =
817 match peek_next_kind_if_operator parser with
818 | None -> (parser, term)
819 | Some token ->
820 let assignment_prefix_kind =
821 check_if_parsable_as_assignment parser term token parser.precedence
823 (* stop parsing expression if:
824 - precedence of the operator is less than precedence of the operator
825 on the left
827 - <term> <operator> does not look like a prefix of
828 some assignment expression*)
829 if operator_has_lower_precedence token parser &&
830 assignment_prefix_kind = Prefix_none then (parser, term)
831 else match token with
832 (* Binary operators *)
833 (* TODO Add an error if PHP and / or / xor are used in Hack. *)
834 (* TODO Add an error if PHP style <> is used in Hack. *)
835 | LessThan when can_term_take_type_args term ->
836 parse_remaining_expression_or_specified_function_call parser term
837 assignment_prefix_kind
838 | And
839 | Or
840 | Xor
841 | Plus
842 | Minus
843 | Star
844 | Slash
845 | StarStar
846 | Equal
847 | BarEqual
848 | PlusEqual
849 | StarEqual
850 | StarStarEqual
851 | SlashEqual
852 | DotEqual
853 | MinusEqual
854 | PercentEqual
855 | CaratEqual
856 | AmpersandEqual
857 | LessThanLessThanEqual
858 | GreaterThanGreaterThanEqual
859 | EqualEqualEqual
860 | LessThan
861 | GreaterThan
862 | Percent
863 | Dot
864 | EqualEqual
865 | AmpersandAmpersand
866 | BarBar
867 | ExclamationEqual
868 | LessThanGreaterThan
869 | ExclamationEqualEqual
870 | LessThanEqual
871 | LessThanEqualGreaterThan
872 | GreaterThanEqual
873 | Ampersand
874 | Bar
875 | LessThanLessThan
876 | GreaterThanGreaterThan
877 | Carat
878 | BarGreaterThan
879 | QuestionQuestion ->
880 parse_remaining_binary_expression parser term assignment_prefix_kind
881 | Instanceof ->
882 parse_instanceof_expression parser term
883 | Is ->
884 parse_is_expression parser term
885 | QuestionMinusGreaterThan
886 | MinusGreaterThan ->
887 let (parser, result) = parse_member_selection_expression parser term in
888 parse_remaining_expression parser result
889 | ColonColon ->
890 let (parser, result) = parse_scope_resolution_expression parser term in
891 parse_remaining_expression parser result
892 | PlusPlus
893 | MinusMinus -> parse_postfix_unary parser term
894 | LeftParen -> parse_function_call parser term
895 | LeftBracket
896 | LeftBrace -> parse_subscript parser term
897 | Question ->
898 let (parser, token) = assert_token parser Question in
899 let (parser, result) = parse_conditional_expression parser term token in
900 parse_remaining_expression parser result
901 | QuestionColon ->
902 parse_remaining_binary_expression parser term assignment_prefix_kind
903 | _ -> (parser, term)
905 and parse_member_selection_expression parser term =
906 (* SPEC:
907 member-selection-expression:
908 postfix-expression -> name
909 postfix-expression -> variable-name
910 postfix-expression -> xhp-class-name (DRAFT XHP SPEC)
912 null-safe-member-selection-expression:
913 postfix-expression ?-> name
914 postfix-expression ?-> variable-name
915 postfix-expression ?-> xhp-class-name (DRAFT XHP SPEC)
917 PHP allows $a->{$b}; to be more compatible with PHP, and give
918 good errors, we allow that here as well.
920 TODO: Produce an error if the braced syntax is used in Hack.
923 let (parser, token) = next_token parser in
924 let op = make_token token in
925 (* TODO: We are putting the name / variable into the tree as a token
926 leaf, rather than as a name or variable expression. Is that right? *)
927 let (parser, name) =
928 match peek_token_kind parser with
929 | LeftBrace ->
930 parse_braced_expression parser
931 | Variable when Env.php5_compat_mode (env parser) ->
932 parse_variable_in_php5_compat_mode parser
933 | Dollar ->
934 parse_dollar_expression parser
935 | _ ->
936 require_xhp_class_name_or_name_or_variable parser in
937 let result = if (Token.kind token) = MinusGreaterThan then
938 make_member_selection_expression term op name
939 else
940 make_safe_member_selection_expression term op name in
941 (parser, result)
943 and parse_variable_in_php5_compat_mode parser =
944 (* PHP7 had a breaking change in parsing variables:
945 (https://wiki.php.net/rfc/uniform_variable_syntax).
946 Hack parser by default uses PHP7 compatible more which interprets
947 variables accesses left-to-right. It usually matches PHP5 behavior
948 except for cases with '$' operator, member accesses and scope resolution
949 operators:
950 $$a[1][2] -> ($$a)[1][2]
951 $a->$b[c] -> ($a->$b)[c]
952 X::$a[b]() -> (X::$a)[b]()
954 In order to preserve backward compatibility we can parse
955 variable/subscript expressions and treat them as if
956 braced expressions to enfore PHP5 semantics
957 $$a[1][2] -> ${$a[1][2]}
958 $a->$b[c] -> $a->{$b[c]}
959 X::$a[b]() -> X::{$a[b]}()
961 let parser1, e =
962 let precedence = Operator.precedence Operator.IndexingOperator in
963 parse_expression (with_precedence parser precedence) in
964 let parser1 = with_precedence parser1 parser.precedence in
965 parser1, e
967 and parse_subscript parser term =
968 (* SPEC
969 subscript-expression:
970 postfix-expression [ expression-opt ]
971 postfix-expression { expression-opt } [Deprecated form]
973 (* TODO: Produce an error for brace case in a later pass *)
974 let (parser, left) = next_token parser in
975 let (parser1, right) = next_token parser in
976 match (Token.kind left, Token.kind right) with
977 | (LeftBracket, RightBracket)
978 | (LeftBrace, RightBrace) ->
979 let left = make_token left in
980 let index = make_missing parser in
981 let right = make_token right in
982 let result = make_subscript_expression term left index right in
983 parse_remaining_expression parser1 result
984 | _ ->
985 begin
986 let (parser, index) = with_reset_precedence parser parse_expression in
987 let (parser, right) = match Token.kind left with
988 | LeftBracket -> require_right_bracket parser
989 | _ -> require_right_brace parser in
990 let left = make_token left in
991 let result = make_subscript_expression term left index right in
992 parse_remaining_expression parser result
995 and parse_expression_list_opt parser =
996 (* SPEC
998 TODO: This business of allowing ... does not appear in the spec. Add it.
1000 TODO: Add call-convention-opt to the specification.
1001 (This work is tracked by task T22582676.)
1003 TODO: Update grammar for inout parameters.
1004 (This work is tracked by task T22582715.)
1006 ERROR RECOVERY: A ... expression can only appear at the end of a
1007 formal parameter list. However, we parse it everywhere without error,
1008 and detect the error in a later pass.
1010 Note that it *is* legal for a ... expression be followed by a trailing
1011 comma, even though it is not legal for such in a formal parameter list.
1013 TODO: Can *any* expression appear after the ... ?
1015 argument-expression-list:
1016 argument-expressions ,-opt
1017 argument-expressions:
1018 expression
1019 ... expression
1020 call-convention-opt expression
1021 argument-expressions , expression
1023 (* This function parses the parens as well. *)
1024 let f parser =
1025 with_reset_precedence parser parse_decorated_expression_opt in
1026 parse_parenthesized_comma_list_opt_allow_trailing parser f
1028 and parse_decorated_expression_opt parser =
1029 match peek_token_kind parser with
1030 | DotDotDot
1031 | Inout ->
1032 let (parser, decorator) = next_token parser in
1033 let (parser, expr) = parse_expression parser in
1034 let decorator = make_token decorator in
1035 parser, make_decorated_expression decorator expr
1036 | _ -> parse_expression parser
1038 and parse_start_of_type_specifier parser start_token =
1039 let (parser, name) =
1040 if Token.kind start_token = Backslash
1041 then scan_qualified_name parser (make_token start_token)
1042 else scan_remaining_qualified_name parser (make_token start_token) in
1043 match peek_token_kind parser with
1044 | LeftParen | LessThan -> Some (parser, name)
1045 | _ -> None
1047 and parse_designator parser =
1048 (* SPEC:
1049 class-type-designator:
1050 parent
1051 self
1052 static
1053 member-selection-expression
1054 null-safe-member-selection-expression
1055 qualified-name
1056 scope-resolution-expression
1057 subscript-expression
1058 variable-name
1060 TODO: Update the spec to allow qualified-name < type arguments >
1061 TODO: This will need to be fixed to allow situations where the qualified name
1062 is also a non-reserved token.
1064 let default parser =
1065 parse_expression_with_operator_precedence parser Operator.NewOperator in
1066 let (parser1, token) = next_token parser in
1067 match Token.kind token with
1068 | Parent
1069 | Self ->
1070 begin match peek_token_kind parser1 with
1071 | LeftParen -> (parser1, make_token token)
1072 | LessThan ->
1073 let parser1, type_arguments =
1074 parse_generic_type_arguments_opt parser1 in
1075 if is_valid_type_argument_list type_arguments parser parser1
1076 then
1077 let type_specifier =
1078 make_generic_type_specifier (make_token token) type_arguments in
1079 parser1, type_specifier
1080 else
1081 default parser
1082 | _ ->
1083 default parser
1085 | Static when peek_token_kind parser1 = LeftParen ->
1086 (parser1, make_token token)
1087 | Name
1088 | Backslash ->
1089 begin match parse_start_of_type_specifier parser1 token with
1090 | Some (parser, name) ->
1091 (* We want to parse new C() and new C<int>() as types, but
1092 new C::$x() as an expression. *)
1093 with_type_parser parser (TypeParser.parse_remaining_type_specifier name)
1094 | None ->
1095 default parser
1097 | _ ->
1098 default parser
1099 (* TODO: We need to verify in a later pass that the expression is a
1100 scope resolution (that does not end in class!), a member selection,
1101 a name, a variable, a property, or an array subscript expression. *)
1103 and parse_object_creation_expression parser =
1104 (* SPEC
1105 object-creation-expression:
1106 new object-creation-what
1108 let (parser, new_token) = assert_token parser New in
1109 let (parser, new_what) =
1110 let (parser1, token) = next_token parser in
1111 begin match Token.kind token with
1112 | Class -> parse_anonymous_class token parser1
1113 | _ -> parse_constructor_call parser
1114 end in
1115 let result = make_object_creation_expression new_token new_what in
1116 (parser, result)
1118 and parse_anonymous_class class_token parser =
1119 let class_token = make_token class_token in
1120 let (parser, left, args, right) =
1121 if peek_token_kind parser = LeftParen
1122 then parse_expression_list_opt parser
1123 else
1124 let missing1 = make_missing parser in
1125 let missing2 = make_missing parser in
1126 let missing3 = make_missing parser in
1127 (parser, missing1, missing2, missing3)
1129 let parser
1130 , ( classish_extends
1131 , classish_extends_list
1132 , classish_implements
1133 , classish_implements_list
1134 , body
1136 = with_decl_parser parser
1137 (fun decl_parser ->
1138 let (decl_parser, classish_extends, classish_extends_list) =
1139 DeclParser.parse_classish_extends_opt decl_parser in
1140 let (decl_parser, classish_implements, classish_implements_list) =
1141 DeclParser.parse_classish_implements_opt decl_parser in
1142 let (decl_parser, body) = DeclParser.parse_classish_body decl_parser in
1143 decl_parser
1144 , ( classish_extends
1145 , classish_extends_list
1146 , classish_implements
1147 , classish_implements_list
1148 , body
1152 let result = make_anonymous_class class_token left args right
1153 classish_extends classish_extends_list classish_implements
1154 classish_implements_list body in
1155 (parser, result)
1157 and parse_constructor_call parser =
1158 (* SPEC
1159 constructor-call:
1160 class-type-designator ( argument-expression-list-opt )
1162 (* PHP allows the entire expression list to be omitted. *)
1163 (* TODO: SPEC ERROR: PHP allows the entire expression list to be omitted,
1164 * but Hack disallows this behavior. (See SyntaxError.error2038.) However,
1165 * the Hack spec still states that the argument expression list is optional.
1166 * Update the spec to say that the argument expression list is required. *)
1167 let (parser, designator) = parse_designator parser in
1168 let (parser, left, args, right) =
1169 if peek_token_kind parser = LeftParen then
1170 parse_expression_list_opt parser
1171 else
1172 let missing1 = make_missing parser in
1173 let missing2 = make_missing parser in
1174 let missing3 = make_missing parser in
1175 (parser, missing1, missing2, missing3)
1177 let result =
1178 make_constructor_call designator left args right in
1179 (parser, result)
1181 and parse_function_call parser receiver =
1182 (* SPEC
1183 function-call-expression:
1184 postfix-expression ( argument-expression-list-opt )
1186 let (parser, left, args, right) = parse_expression_list_opt parser in
1187 let result = make_function_call_expression receiver left args right in
1188 parse_remaining_expression parser result
1190 and parse_variable_or_lambda parser =
1191 let (parser1, variable) = assert_token parser Variable in
1192 if peek_token_kind parser1 = EqualEqualGreaterThan then
1193 parse_lambda_expression parser
1194 else
1195 (parser1, make_variable_expression variable)
1197 and parse_yield_expression parser =
1198 (* SPEC:
1199 yield array-element-initializer
1200 TODO: Hack allows "yield break".
1201 TODO: Should this be its own production, or can it be a yield expression?
1202 TODO: Is this an expression or a statement?
1203 TODO: Add it to the specification.
1205 let parser, yield_kw = assert_token parser Yield in
1206 match peek_token_kind parser with
1207 | From ->
1208 let parser, from_kw = assert_token parser From in
1209 let parser, operand = parse_expression parser in
1210 parser, make_yield_from_expression yield_kw from_kw operand
1211 | Break ->
1212 let parser, break_kw = assert_token parser Break in
1213 parser, make_yield_expression yield_kw break_kw
1214 | Semicolon ->
1215 let missing = make_missing parser in
1216 let yield_expr = make_yield_expression yield_kw missing in
1217 parser, yield_expr
1218 | _ ->
1219 let parser, operand = parse_array_element_init parser in
1220 parser, make_yield_expression yield_kw operand
1222 and parse_cast_or_parenthesized_or_lambda_expression parser =
1223 (* We need to disambiguate between casts, lambdas and ordinary
1224 parenthesized expressions. *)
1225 match possible_cast_expression parser with
1226 | Some (parser, left, cast_type, right) ->
1227 let (parser, operand) = parse_expression_with_operator_precedence
1228 parser Operator.CastOperator in
1229 let result = make_cast_expression left cast_type right operand in
1230 (parser, result)
1231 | _ -> begin
1232 match possible_lambda_expression parser with
1233 | Some (parser, signature) ->
1234 parse_lambda_expression_after_signature parser signature
1235 | None ->
1236 parse_parenthesized_expression parser
1239 and token_implies_cast kind =
1240 (* See comments below. *)
1241 match kind with
1242 (* Keywords that imply cast *)
1243 | Abstract
1244 | Array
1245 | Arraykey
1246 | Async
1247 | TokenKind.Attribute
1248 | Await
1249 | Bool
1250 | Break
1251 | Case
1252 | Catch
1253 | Category
1254 | Children
1255 | Class
1256 | Classname
1257 | Clone
1258 | Const
1259 | Construct
1260 | Continue
1261 | Coroutine
1262 | Darray
1263 | Dict
1264 | Default
1265 | Define
1266 | HaltCompiler
1267 | Declare
1268 | Destruct
1269 | Do
1270 | Double
1271 | Echo
1272 | Else
1273 | Elseif
1274 | Empty
1275 | Endif
1276 | Endfor
1277 | Enum
1278 | Eval
1279 | Extends
1280 | Fallthrough
1281 | Float
1282 | Final
1283 | Finally
1284 | For
1285 | Foreach
1286 | From
1287 | Function
1288 | Global
1289 | Goto
1290 | If
1291 | Implements
1292 | Include
1293 | Include_once
1294 | Inout
1295 | Insteadof
1296 | Int
1297 | Interface
1298 | Isset
1299 | Keyset
1300 | List
1301 | Mixed
1302 | Namespace
1303 | New
1304 | Newtype
1305 | Noreturn
1306 | Num
1307 | Object
1308 | Parent
1309 | Print
1310 | Private
1311 | Protected
1312 | Public
1313 | Require
1314 | Require_once
1315 | Required
1316 | Resource
1317 | Return
1318 | Self
1319 | Shape
1320 | Static
1321 | String
1322 | Super
1323 | Suspend
1324 | Switch
1325 | This
1326 | Throw
1327 | Trait
1328 | Try
1329 | Tuple
1330 | Type
1331 | Unset
1332 | Use
1333 | Using
1334 | Var
1335 | Varray
1336 | Vec
1337 | Void
1338 | Where
1339 | While
1340 | Yield -> true
1341 (* Names that imply cast *)
1342 | Name
1343 | Backslash
1344 | Variable -> true
1345 (* Symbols that imply cast *)
1346 | At
1347 | DollarDollar
1348 | Exclamation
1349 | LeftParen
1350 | Minus
1351 | MinusMinus
1352 | Dollar
1353 | Plus
1354 | PlusPlus
1355 | Tilde -> true
1356 (* Literals that imply cast *)
1357 | BinaryLiteral
1358 | BooleanLiteral
1359 | DecimalLiteral
1360 | DoubleQuotedStringLiteral
1361 | DoubleQuotedStringLiteralHead
1362 | StringLiteralBody
1363 | DoubleQuotedStringLiteralTail
1364 | ExecutionStringLiteral
1365 | ExecutionStringLiteralHead
1366 | ExecutionStringLiteralTail
1367 | FloatingLiteral
1368 | HeredocStringLiteral
1369 | HeredocStringLiteralHead
1370 | HeredocStringLiteralTail
1371 | HexadecimalLiteral
1372 | NowdocStringLiteral
1373 | NullLiteral
1374 | OctalLiteral
1375 | SingleQuotedStringLiteral -> true
1376 (* Keywords that imply parenthesized expression *)
1377 | And
1378 | As
1379 | Instanceof
1380 | Is
1381 | Or
1382 | Xor -> false
1383 (* Symbols that imply parenthesized expression *)
1384 | Ampersand
1385 | AmpersandAmpersand
1386 | AmpersandEqual
1387 | Bar
1388 | BarBar
1389 | BarEqual
1390 | BarGreaterThan
1391 | Carat
1392 | CaratEqual
1393 | Colon
1394 | ColonColon
1395 | Comma
1396 | Dot
1397 | DotEqual
1398 | DotDotDot
1399 | Equal
1400 | EqualEqual
1401 | EqualEqualEqual
1402 | EqualEqualGreaterThan
1403 | EqualGreaterThan
1404 | ExclamationEqual
1405 | LessThanGreaterThan
1406 | ExclamationEqualEqual
1407 | GreaterThan
1408 | GreaterThanEqual
1409 | GreaterThanGreaterThan
1410 | GreaterThanGreaterThanEqual
1411 | LessThanLessThanEqual
1412 | MinusEqual
1413 | MinusGreaterThan
1414 | Question
1415 | QuestionMinusGreaterThan
1416 | QuestionQuestion
1417 | QuestionColon
1418 | RightBrace
1419 | RightBracket
1420 | RightParen
1421 | LeftBrace
1422 | LeftBracket
1423 | LessThan
1424 | LessThanEqual
1425 | LessThanEqualGreaterThan
1426 | LessThanLessThan
1427 | Percent
1428 | PercentEqual
1429 | PlusEqual
1430 | Semicolon
1431 | Slash
1432 | SlashEqual
1433 | SlashGreaterThan
1434 | Star
1435 | StarEqual
1436 | StarStar
1437 | StarStarEqual -> false
1438 (* Misc *)
1439 | Markup
1440 | LessThanQuestion
1441 | QuestionGreaterThan
1442 | ErrorToken
1443 | TokenKind.EndOfFile -> false
1444 (* TODO: Sort out rules for interactions between casts and XHP. *)
1445 | LessThanSlash
1446 | XHPCategoryName
1447 | XHPElementName
1448 | XHPClassName
1449 | XHPStringLiteral
1450 | XHPBody
1451 | XHPComment -> false
1453 and possible_cast_expression parser =
1454 (* SPEC:
1455 cast-expression:
1456 ( cast-type ) unary-expression
1457 cast-type:
1458 array, bool, double, float, int, object, string, unset or a name
1460 TODO: This implies that a cast "(name)" can only be a simple name, but
1461 I would expect that (\Foo\Bar), (:foo), (array<int>), and the like
1462 should also be legal casts. If we implement that then we will need
1463 a sophisticated heuristic to determine whether this is a cast or a
1464 parenthesized expression.
1466 The cast expression introduces an ambiguity: (x)-y could be a
1467 subtraction or a cast on top of a unary minus. We resolve this
1468 ambiguity as follows:
1470 * If the thing in parens is one of the keywords mentioned above, then
1471 it's a cast.
1472 * If the token which follows (x) is "as" or "instanceof" then
1473 it's a parenthesized expression.
1474 * PHP-ism extension: if the token is "and", "or" or "xor", then it's a
1475 parenthesized expression.
1476 * Otherwise, if the token which follows (x) is $$, @, ~, !, (, +, -,
1477 any name, qualified name, variable name, literal, or keyword then
1478 it's a cast.
1479 * Otherwise, it's a parenthesized expression. *)
1481 let (parser, left_paren) = assert_token parser LeftParen in
1482 let (parser, type_token) = next_token parser in
1483 let type_token_kind = Token.kind type_token in
1484 let (parser, right_paren) = next_token parser in
1485 let is_easy_cast_type_or_at_least_name =
1486 match type_token_kind with
1487 | Array | Bool | Double | Float | Int | Object | String | Unset -> Some true
1488 | Name -> Some false
1489 | _ -> None in
1490 let is_cast = Token.kind right_paren = RightParen &&
1491 Option.value_map ~default:false is_easy_cast_type_or_at_least_name
1492 ~f:(fun b -> b || token_implies_cast (peek_token_kind parser)) in
1493 if is_cast then
1494 Some (parser, left_paren, make_token type_token, make_token right_paren)
1495 else
1496 None
1498 and possible_lambda_expression parser =
1499 (* We have a left paren in hand and we already know we're not in a cast.
1500 We need to know whether this is a parenthesized expression or the
1501 signature of a lambda.
1503 There are a number of difficulties. For example, we cannot simply
1504 check to see if a colon follows the expression:
1506 $a = $b ? ($x) : ($y) ($x) is parenthesized expression
1507 $a = $b ? ($x) : int ==> 1 : ($y) ($x) is lambda signature
1509 ERROR RECOVERY:
1511 What we'll do here is simply attempt to parse a lambda formal parameter
1512 list. If we manage to do so *without error*, and the thing which follows
1513 is ==>, then this is definitely a lambda. If those conditions are not
1514 met then we assume we have a parenthesized expression in hand.
1516 TODO: There could be situations where we have good evidence that a
1517 lambda is intended but these conditions are not met. Consider
1518 a more sophisticated recovery strategy. For example, if we have
1519 (x)==> then odds are pretty good that a lambda was intended and the
1520 error should say that ($x)==> was expected.
1522 let signature_result = parse_if_no_error parser parse_lambda_signature in
1523 match signature_result with
1524 | Some (parser, _) when (peek_token_kind parser) = EqualEqualGreaterThan ->
1525 signature_result
1526 | _ -> None
1528 and parse_lambda_expression parser =
1529 (* SPEC
1530 lambda-expression:
1531 async-opt lambda-function-signature ==> lambda-body
1533 let (parser, async) = optional_token parser Async in
1534 let (parser, coroutine) = optional_token parser Coroutine in
1535 let (parser, signature) = parse_lambda_signature parser in
1536 let (parser, arrow) = require_lambda_arrow parser in
1537 let (parser, body) = parse_lambda_body parser in
1538 let result = make_lambda_expression async coroutine signature arrow body in
1539 (parser, result)
1541 and parse_lambda_expression_after_signature parser signature =
1542 (* We had a signature with no async or coroutine, and we disambiguated it
1543 from a cast. *)
1544 let async = make_missing parser in
1545 let coroutine = make_missing parser in
1546 let (parser, arrow) = require_lambda_arrow parser in
1547 let (parser, body) = parse_lambda_body parser in
1548 let result = make_lambda_expression async coroutine signature arrow body in
1549 (parser, result)
1551 and parse_lambda_signature parser =
1552 (* SPEC:
1553 lambda-function-signature:
1554 variable-name
1555 ( anonymous-function-parameter-declaration-list-opt ) /
1556 anonymous-function-return-opt
1558 let (parser1, token) = next_token parser in
1559 if Token.kind token = Variable then
1560 (parser1, make_token token)
1561 else
1562 let (parser, left, params, right) = parse_parameter_list_opt parser in
1563 let (parser, colon, return_type) = parse_optional_return parser in
1564 let result = make_lambda_signature left params right colon return_type in
1565 (parser, result)
1567 and parse_lambda_body parser =
1568 (* SPEC:
1569 lambda-body:
1570 expression
1571 compound-statement
1573 if peek_token_kind parser = LeftBrace then
1574 parse_compound_statement parser
1575 else
1576 with_reset_precedence parser parse_expression
1578 and parse_parenthesized_expression parser =
1579 let (parser, left_paren) = assert_token parser LeftParen in
1580 let (parser, expression) = with_reset_precedence parser parse_expression in
1581 let (parser, right_paren) = require_right_paren parser in
1582 let syntax =
1583 make_parenthesized_expression left_paren expression right_paren in
1584 (parser, syntax)
1586 and parse_postfix_unary parser term =
1587 let (parser, token) = next_token parser in
1588 let term = make_postfix_unary_expression term (make_token token) in
1589 parse_remaining_expression parser term
1591 and parse_prefix_unary_expression parser =
1592 (* TODO: Operand to ++ and -- must be an lvalue. *)
1593 let (parser, token) = next_token parser in
1594 let kind = Token.kind token in
1595 let operator = Operator.prefix_unary_from_token kind in
1596 let token = make_token token in
1597 let (parser, operand) = parse_expression_with_operator_precedence
1598 parser operator in
1599 make_and_track_prefix_unary_expression parser token kind operand
1601 and parse_simple_variable parser =
1602 match peek_token_kind parser with
1603 | Variable ->
1604 let (parser1, variable) = next_token parser in
1605 (parser1, make_token variable)
1606 | Dollar -> parse_dollar_expression parser
1607 | _ -> require_variable parser
1609 and parse_dollar_expression parser =
1610 let (parser, dollar) = assert_token parser Dollar in
1611 let (parser, operand) =
1612 match peek_token_kind parser with
1613 | LeftBrace ->
1614 parse_braced_expression parser
1615 | Variable when Env.php5_compat_mode (env parser) ->
1616 parse_variable_in_php5_compat_mode parser
1617 | _ ->
1618 parse_expression_with_operator_precedence parser
1619 (Operator.prefix_unary_from_token Dollar) in
1620 make_and_track_prefix_unary_expression parser dollar Dollar operand
1622 and parse_instanceof_expression parser left =
1623 (* SPEC:
1624 instanceof-expression:
1625 instanceof-subject instanceof instanceof-type-designator
1627 instanceof-subject:
1628 expression
1630 instanceof-type-designator:
1631 qualified-name
1632 variable-name
1634 TODO: The spec is plainly wrong here. This is a bit of a mess and there
1635 are a number of issues.
1637 The issues arise from the fact that the thing on the right can be either
1638 a type, or an expression that evaluates to a string that names the type.
1640 The grammar in the spec, above, says that the only things that can be
1641 here are a qualified name -- in which case it names the type directly --
1642 or a variable of classname type, which names the type. But this is
1643 not the grammar that is accepted by Hack / HHVM. The accepted grammar
1644 treats "instanceof" as a binary operator which takes expressions on
1645 each side, and is of lower precedence than ->. Thus
1647 $x instanceof $y -> z
1649 must be parsed as ($x instanceof ($y -> z)), and not, as the grammar
1650 implies, (($x instanceof $y) -> z).
1652 But wait, it gets worse.
1654 The less-than operator is of lower precedence than instanceof, so
1655 "$x instanceof foo < 10" should be parsed as (($x instanceof foo) < 10).
1656 But it seems plausible that we might want to parse
1657 "$x instanceof foo<int>" someday, in which case now we have an ambiguity.
1658 How do we know when we see the < whether we are attempting to parse a type?
1660 Moreover: we need to be able to parse XHP class names on the right hand
1661 side of the operator. That is, we need to be able to say
1663 $x instanceof :foo
1665 However, we cannot simply say that the grammar is
1667 instanceof-type-designator:
1668 xhp-class-name
1669 expression
1671 Why not? Because that then gives the wrong parse for:
1673 class :foo { static $bar = "abc" }
1674 class abc { }
1676 $x instanceof :foo :: $bar
1678 We need to parse that as $x instanceof (:foo :: $bar).
1680 The solution to all this is as follows.
1682 First, an XHP class name must be a legal expression. I had thought that
1683 it might be possible to say that an XHP class name is a legal type, or
1684 legal in an expression context when immediately followed by ::, but
1685 that's not the case. We need to be able to parse both
1687 $x instanceof :foo :: $bar
1691 $x instanceof :foo
1693 so the most expedient way to do that is to parse any expression on the
1694 right, and to make XHP class names into legal expressions.
1696 So, with all this in mind, the grammar we will actually parse here is:
1698 instanceof-type-designator:
1699 expression
1701 This has the unfortunate property that the common case, say,
1703 $x instanceof C
1705 creates a parse node for C as a name token, not as a name token wrapped
1706 up as a simple type.
1708 Should we ever need to parse both arbitrary expressions and arbitrary
1709 types here, we'll have some tricky problems to solve.
1712 let (parser, op) = assert_token parser Instanceof in
1713 let precedence = Operator.precedence Operator.InstanceofOperator in
1714 let (parser, right_term) = parse_term parser in
1715 let (parser, right) = parse_remaining_binary_expression_helper
1716 parser right_term precedence in
1717 let result = make_instanceof_expression left op right in
1718 parse_remaining_expression parser result
1720 and parse_is_expression parser left =
1721 (* SPEC:
1722 is-expression:
1723 is-subject is type-specifier
1725 is-subject:
1726 expression
1728 let (parser, op) = assert_token parser Is in
1729 let (parser, right) =
1730 with_type_parser parser TypeParser.parse_type_specifier
1732 let result = make_is_expression left op right in
1733 parse_remaining_expression parser result
1735 and parse_remaining_binary_expression
1736 parser left_term assignment_prefix_kind =
1737 (* We have a left term. If we get here then we know that
1738 * we have a binary operator to its right, and that furthermore,
1739 * the binary operator is of equal or higher precedence than the
1740 * whatever is going on in the left term.
1742 * Here's how this works. Suppose we have something like
1744 * A x B y C
1746 * where A, B and C are terms, and x and y are operators.
1747 * We must determine whether this parses as
1749 * (A x B) y C
1751 * or
1753 * A x (B y C)
1755 * We have the former if either x is higher precedence than y,
1756 * or x and y are the same precedence and x is left associative.
1757 * Otherwise, if x is lower precedence than y, or x is right
1758 * associative, then we have the latter.
1760 * How are we going to figure this out?
1762 * We have the term A in hand; the precedence is low.
1763 * We see that x follows A.
1764 * We obtain the precedence of x. It is higher than the precedence of A,
1765 * so we obtain B, and then we call a helper method that
1766 * collects together everything to the right of B that is
1767 * of higher precedence than x. (Or equal, and right-associative.)
1769 * So, if x is of lower precedence than y (or equal and right-assoc)
1770 * then the helper will construct (B y C) as the right term, and then
1771 * we'll make A x (B y C), and we're done. Otherwise, the helper
1772 * will simply return B, we'll construct (A x B) and recurse with that
1773 * as the left term.
1775 let is_rhs_of_assignment = assignment_prefix_kind <> Prefix_none in
1776 assert (not (next_is_lower_precedence parser) || is_rhs_of_assignment);
1778 let (parser1, token) = next_token parser in
1779 let operator = Operator.trailing_from_token (Token.kind token) in
1780 let default () =
1781 let precedence = Operator.precedence operator in
1782 let (parser2, right_term) =
1783 if is_rhs_of_assignment then
1784 (* reset the current precedence to make sure that expression on
1785 the right hand side of the assignment is fully consumed *)
1786 with_reset_precedence parser1 parse_term
1787 else
1788 parse_term parser1 in
1789 let (parser2, right_term) = parse_remaining_binary_expression_helper
1790 parser2 right_term precedence in
1791 let term = make_binary_expression
1792 left_term (make_token token) right_term in
1793 parse_remaining_expression parser2 term
1795 (*if we are on the right hand side of the assignment - peek if next
1796 token is '&'. If it is - then parse next term. If overall next term is
1797 '&'PHP variable then the overall expression should be parsed as
1798 ... (left_term = & right_term) ...
1800 if assignment_prefix_kind = Prefix_byref_assignment &&
1801 Token.kind (peek_token parser1) = Ampersand then
1802 let (parser2, right_term) =
1803 parse_term @@ with_precedence
1804 parser1
1805 Operator.precedence_for_assignment_in_expressions in
1806 if is_byref_assignment_source parser2 right_term then
1807 let left_term = make_binary_expression
1808 left_term (make_token token) right_term
1810 let (parser2, left_term) = parse_remaining_binary_expression_helper
1811 parser2 left_term parser.precedence
1813 parse_remaining_expression parser2 left_term
1814 else
1815 default ()
1816 else
1817 default ()
1819 and parse_remaining_binary_expression_helper
1820 parser right_term left_precedence =
1821 (* This gathers up terms to the right of an operator that are
1822 operands of operators of higher precedence than the
1823 operator to the left. For instance, if we have
1824 A + B * C / D + E and we just parsed A +, then we want to
1825 gather up B * C / D into the right side of the +.
1826 In this case "right term" would be B and "left precedence"
1827 would be the precedence of +.
1828 See comments above for more details. *)
1829 let kind = Token.kind (peek_token parser) in
1830 if Operator.is_trailing_operator_token kind then
1831 let right_operator = Operator.trailing_from_token kind in
1832 let right_precedence = Operator.precedence right_operator in
1833 let associativity = Operator.associativity right_operator in
1834 let is_parsable_as_assignment =
1835 (* check if this is the case ... $a = ...
1836 where
1837 'left_precedence' - precedence of the operation on the left of $a
1838 'rigft_term' - $a
1839 'kind' - operator that follows right_term
1841 in case if right_term is valid left hand side for the assignment
1842 and token is assignment operator and left_precedence is less than
1843 bumped priority fort the assignment we reset precedence before parsing
1844 right hand side of the assignment to make sure it is consumed.
1846 check_if_parsable_as_assignment
1847 parser
1848 right_term
1849 kind
1850 left_precedence <> Prefix_none
1852 if right_precedence > left_precedence ||
1853 (associativity = Operator.RightAssociative &&
1854 right_precedence = left_precedence ) ||
1855 is_parsable_as_assignment then
1856 let (parser2, right_term) =
1857 let precedence =
1858 if is_parsable_as_assignment then
1859 (* if expression can be parsed as an assignment, keep track of
1860 the precedence on the left of the assignment (it is ok since
1861 we'll internally boost the precedence when parsing rhs of the
1862 assignment)
1863 This is necessary for cases like:
1864 ... + $a = &$b * $c + ...
1867 it should be parsed as
1868 (... + ($a = &$b) * $c) + ...
1869 when we are at position (#)
1870 - we will first consume byref assignment as a e1
1871 - check that precedence of '*' is greater than precedence of
1872 the '+' (left_precedence) and consume e1 * $c as $e2
1873 - check that precedence of '+' is less or equal than precedence
1874 of the '+' (left_precedence) and stop so the final result
1875 before we get to the point ($) will be
1876 (... + $e2)
1878 left_precedence
1879 else
1880 right_precedence
1882 let parser1 = with_precedence parser precedence in
1883 parse_remaining_expression parser1 right_term
1885 let parser3 = with_precedence parser2 parser.precedence in
1886 parse_remaining_binary_expression_helper
1887 parser3 right_term left_precedence
1888 else
1889 (parser, right_term)
1890 else
1891 (parser, right_term)
1893 and parse_conditional_expression parser test question =
1894 (* POSSIBLE SPEC PROBLEM
1895 We allow any expression, including assignment expressions, to be in
1896 the consequence and alternative of a conditional expression, even
1897 though assignment is lower precedence than ?:. This is legal:
1898 $a ? $b = $c : $d = $e
1899 Interestingly, this is illegal in C and Java, which require parens,
1900 but legal in C#.
1902 let kind = peek_token_kind parser in
1903 (* e1 ?: e2 -- where there is no consequence -- is legal.
1904 However this introduces an ambiguity:
1905 x ? :y::m : z
1906 is that
1907 x ?: y::m : z
1909 x ? :y::m : z
1911 We assume the latter.
1912 TODO: Review this decision.
1913 TODO: Add this to the XHP draft specification.
1915 let missing_consequence =
1916 kind = Colon && not (is_next_xhp_class_name parser) in
1917 let (parser, consequence) =
1918 if missing_consequence then
1919 let missing = make_missing parser in
1920 (parser, missing)
1921 else
1922 with_reset_precedence parser parse_expression
1924 let (parser, colon) = require_colon parser in
1925 let (parser, term) = parse_term parser in
1926 let precedence = Operator.precedence Operator.ConditionalQuestionOperator in
1927 let (parser, alternative) = parse_remaining_binary_expression_helper
1928 parser term precedence in
1929 let result = make_conditional_expression
1930 test question consequence colon alternative in
1931 (parser, result)
1933 and parse_name_or_collection_literal_expression parser name =
1934 match peek_token_kind parser with
1935 | LeftBrace ->
1936 let name = make_simple_type_specifier name in
1937 parse_collection_literal_expression parser name
1938 | LessThan ->
1939 let parser1, type_arguments =
1940 parse_generic_type_arguments_opt parser in
1941 if is_valid_type_argument_list type_arguments parser parser1
1942 && peek_token_kind parser1 = LeftBrace
1943 then
1944 let name = make_generic_type_specifier name type_arguments in
1945 parse_collection_literal_expression parser1 name
1946 else
1947 (parser, name)
1948 | _ ->
1949 (parser, name)
1951 and parse_collection_literal_expression parser name =
1953 (* SPEC
1954 collection-literal:
1955 key-collection-class-type { cl-initializer-list-with-keys-opt }
1956 non-key-collection-class-type { cl-initializer-list-without-keys-opt }
1957 pair-type { cl-element-value , cl-element-value }
1959 The types are grammatically qualified names; however the specification
1960 states that they must be as follows:
1961 * keyed collection type can be Map or ImmMap
1962 * non-keyed collection type can be Vector, ImmVector, Set or ImmSet
1963 * pair type can be Pair
1965 We will not attempt to determine if the names give the name of an
1966 appropriate type here. That's for the type checker.
1968 The argumment lists are:
1970 * for keyed, an optional comma-separated list of
1971 expression => expression pairs
1972 * for non-keyed, an optional comma-separated list of expressions
1973 * for pairs, a comma-separated list of exactly two expressions
1975 In all three cases, the lists may be comma-terminated.
1976 TODO: This fact is not represented in the specification; it should be.
1977 This work item is tracked by spec issue #109.
1980 let (parser, left_brace, initialization_list, right_brace) =
1981 parse_braced_comma_list_opt_allow_trailing parser parse_init_expression in
1982 (* Validating the name is a collection type happens in a later phase *)
1983 let syntax = make_collection_literal_expression
1984 name left_brace initialization_list right_brace in
1985 (parser, syntax)
1987 and parse_init_expression parser =
1988 (* ERROR RECOVERY
1989 We expect either a list of expr, expr, expr, ... or
1990 expr => expr, expr => expr, expr => expr, ...
1991 Rather than require at parse time that the list be all one or the other,
1992 we allow both, and give an error in the type checker.
1994 let parser, expr1 = parse_expression_with_reset_precedence parser in
1995 let parser, arrow = optional_token parser TokenKind.EqualGreaterThan in
1996 if is_missing arrow then
1997 (parser, expr1)
1998 else
1999 let parser, expr2 = parse_expression_with_reset_precedence parser in
2000 let syntax = make_element_initializer expr1 arrow expr2 in
2001 (parser, syntax)
2003 and parse_keyed_element_initializer parser =
2004 let parser, expr1 = parse_expression_with_reset_precedence parser in
2005 let parser, arrow = require_arrow parser in
2006 let parser, expr2 = parse_expression_with_reset_precedence parser in
2007 let syntax = make_element_initializer expr1 arrow expr2 in
2008 (parser, syntax)
2010 and parse_list_expression parser =
2011 (* SPEC:
2012 list-intrinsic:
2013 list ( expression-list-opt )
2014 expression-list:
2015 expression-opt
2016 expression-list , expression-opt
2018 See https://github.com/hhvm/hack-langspec/issues/82
2020 list-intrinsic must be used as the left-hand operand in a
2021 simple-assignment-expression of which the right-hand operand
2022 must be an expression that designates a vector-like array or
2023 an instance of the class types Vector, ImmVector, or Pair
2024 (the "source").
2026 TODO: Produce an error later if the expressions in the list destructuring
2027 are not lvalues.
2029 let (parser, keyword) = assert_token parser List in
2030 let (parser, left, items, right) =
2031 parse_parenthesized_comma_list_opt_items_opt
2032 parser parse_expression_with_reset_precedence in
2033 let result = make_list_expression keyword left items right in
2034 (parser, result)
2036 (* grammar:
2037 * array_intrinsic := array ( array-initializer-opt )
2039 and parse_array_intrinsic_expression parser =
2040 let (parser, array_keyword) = assert_token parser Array in
2041 let (parser, left_paren, members, right_paren) =
2042 parse_parenthesized_comma_list_opt_allow_trailing
2043 parser parse_array_element_init in
2044 let syntax = make_array_intrinsic_expression array_keyword left_paren
2045 members right_paren in
2046 (parser, syntax)
2048 and parse_bracketed_collection_intrinsic_expression
2049 parser
2050 keyword_token
2051 parse_element_function
2052 make_intrinsinc_function =
2053 let (parser1, keyword) = assert_token parser keyword_token in
2054 let (parser1, left_bracket) = optional_token parser1 LeftBracket in
2055 if is_missing left_bracket then
2056 (* Fall back to dict being an ordinary name. Perhaps we're calling a
2057 function whose name is indicated by the keyword_token, for example. *)
2058 parse_as_name_or_error parser
2059 else
2060 let (parser, members) =
2061 parse_comma_list_opt_allow_trailing
2062 parser1
2063 RightBracket
2064 SyntaxError.error1015
2065 parse_element_function in
2066 let (parser, right_bracket) = require_right_bracket parser in
2067 let result =
2068 make_intrinsinc_function keyword left_bracket members right_bracket in
2069 (parser, result)
2072 and parse_darray_intrinsic_expression parser =
2073 (* TODO: Create the grammar and add it to the spec. *)
2074 parse_bracketed_collection_intrinsic_expression
2075 parser
2076 Darray
2077 parse_keyed_element_initializer
2078 make_darray_intrinsic_expression
2080 and parse_dictionary_intrinsic_expression parser =
2081 (* TODO: Create the grammar and add it to the spec. *)
2082 (* TODO: Can the list have a trailing comma? *)
2083 parse_bracketed_collection_intrinsic_expression
2084 parser
2085 Dict
2086 parse_keyed_element_initializer
2087 make_dictionary_intrinsic_expression
2089 and parse_keyset_intrinsic_expression parser =
2090 parse_bracketed_collection_intrinsic_expression
2091 parser
2092 Keyset
2093 parse_expression_with_reset_precedence
2094 make_keyset_intrinsic_expression
2096 and parse_varray_intrinsic_expression parser =
2097 (* TODO: Create the grammar and add it to the spec. *)
2098 parse_bracketed_collection_intrinsic_expression
2099 parser
2100 Varray
2101 parse_expression_with_reset_precedence
2102 make_varray_intrinsic_expression
2104 and parse_vector_intrinsic_expression parser =
2105 (* TODO: Create the grammar and add it to the spec. *)
2106 (* TODO: Can the list have a trailing comma? *)
2107 parse_bracketed_collection_intrinsic_expression
2108 parser
2110 parse_expression_with_reset_precedence
2111 make_vector_intrinsic_expression
2113 (* array_creation_expression :=
2114 [ array-initializer-opt ]
2115 array-initializer :=
2116 array-initializer-list ,-opt
2117 array-initializer-list :=
2118 array-element-initializer
2119 array-element-initializer , array-initializer-list
2121 and parse_array_creation_expression parser =
2122 let (parser, left_bracket, members, right_bracket) =
2123 parse_bracketted_comma_list_opt_allow_trailing
2124 parser parse_array_element_init in
2125 let syntax = make_array_creation_expression left_bracket
2126 members right_bracket in
2127 (parser, syntax)
2129 (* array-element-initializer :=
2130 * expression
2131 * expression => expression
2133 and parse_array_element_init parser =
2134 let parser, expr1 =
2135 with_reset_precedence parser parse_expression in
2136 let parser1, token = next_token parser in
2137 match Token.kind token with
2138 | EqualGreaterThan ->
2139 let parser, expr2 = with_reset_precedence parser1 parse_expression in
2140 let arrow = make_token token in
2141 let result = make_element_initializer expr1 arrow expr2 in
2142 (parser, result)
2143 | _ -> (parser, expr1)
2145 and parse_field_initializer parser =
2146 (* SPEC
2147 field-initializer:
2148 single-quoted-string-literal => expression
2149 double_quoted_string_literal => expression
2150 qualified-name => expression
2151 scope-resolution-expression => expression
2154 (* Specification is wrong, and fixing it is being tracked by
2155 * https://github.com/hhvm/hack-langspec/issues/108
2158 (* ERROR RECOVERY: We allow any expression on the left-hand side,
2159 * even though only some expressions are legal;
2160 * we will give an error in a later pass
2162 let (parser, name) = with_reset_precedence parser parse_expression in
2163 let (parser, arrow) = require_arrow parser in
2164 let (parser, value) = with_reset_precedence parser parse_expression in
2165 let result = make_field_initializer name arrow value in
2166 (parser, result)
2168 and parse_shape_expression parser =
2169 (* SPEC
2170 shape-literal:
2171 shape ( field-initializer-list-opt )
2173 field-initializer-list:
2174 field-initializers ,-op
2176 field-initializers:
2177 field-initializer
2178 field-initializers , field-initializer
2180 let (parser, shape) = assert_token parser Shape in
2181 let (parser, left_paren, fields, right_paren) =
2182 parse_parenthesized_comma_list_opt_allow_trailing
2183 parser parse_field_initializer in
2184 let result = make_shape_expression shape left_paren fields right_paren in
2185 (parser, result)
2187 and parse_tuple_expression parser =
2188 (* SPEC
2189 tuple-literal:
2190 tuple ( expression-list-one-or-more )
2192 expression-list-one-or-more:
2193 expression
2194 expression-list-one-or-more , expression
2196 TODO: Can the list be comma-terminated? If so, update the spec.
2197 TODO: We need to produce an error in a later pass if the list is empty.
2199 let (parser, keyword) = assert_token parser Tuple in
2200 let (parser, left_paren, items, right_paren) =
2201 parse_parenthesized_comma_list_opt_allow_trailing
2202 parser parse_expression_with_reset_precedence in
2203 let result = make_tuple_expression keyword left_paren items right_paren in
2204 (parser, result)
2206 and parse_use_variable parser =
2207 (* TODO: Is it better that this returns the variable as a *token*, or
2208 as an *expression* that consists of the token? We do the former. *)
2209 let (parser, ampersand) = optional_token parser Ampersand in
2210 let (parser, variable) = require_variable parser in
2211 if is_missing ampersand then
2212 (parser, variable)
2213 else
2214 make_and_track_prefix_unary_expression parser ampersand Ampersand variable
2216 and parse_anon_or_lambda_or_awaitable parser =
2217 (* TODO: The original Hack parser accepts "async" as an identifier, and
2218 so we do too. We might consider making it reserved. *)
2219 (* Skip any async or coroutine declarations that may be present. When we
2220 feed the original parser into the syntax parsers. they will take care of
2221 them as appropriate. *)
2222 let (parser1, _) = optional_token parser Static in
2223 let (parser1, _) = optional_token parser1 Async in
2224 let (parser1, _) = optional_token parser1 Coroutine in
2225 match peek_token_kind parser1 with
2226 | Function -> parse_anon parser
2227 | LeftBrace -> parse_async_block parser
2228 | Variable
2229 | LeftParen -> parse_lambda_expression parser
2230 | _ -> parse_as_name_or_error parser
2232 and parse_async_block parser =
2234 * grammar:
2235 * awaitable-creation-expression :
2236 * async-opt coroutine-opt compound-statement
2237 * TODO awaitable-creation-expression must not be used as the
2238 * anonymous-function-body in a lambda-expression
2240 let parser, async = optional_token parser Async in
2241 let parser, coroutine = optional_token parser Coroutine in
2242 let parser, stmt = parse_compound_statement parser in
2243 parser, make_awaitable_creation_expression async coroutine stmt
2245 and parse_anon_use_opt parser =
2246 (* SPEC:
2247 anonymous-function-use-clause:
2248 use ( use-variable-name-list ,-opt )
2250 use-variable-name-list:
2251 variable-name
2252 use-variable-name-list , variable-name
2254 TODO: Strict mode requires that it be a list of variables; in
2255 non-strict mode we allow variables to be decorated with a leading
2256 & to indicate they are captured by reference. We need to give an
2257 error in a later pass for this.
2259 let (parser, use_token) = optional_token parser Use in
2260 if is_missing use_token then
2261 let missing = make_missing parser in
2262 (parser, missing)
2263 else
2264 let (parser, left, vars, right) =
2265 parse_parenthesized_comma_list_opt_allow_trailing
2266 parser parse_use_variable in
2267 let result = make_anonymous_function_use_clause use_token
2268 left vars right
2270 (parser, result)
2272 and parse_optional_return parser =
2273 (* Parse an optional "colon-folowed-by-return-type" *)
2274 let (parser, colon) = optional_token parser Colon in
2275 let (parser, return_type) =
2276 if is_missing colon then
2277 let missing = make_missing parser in
2278 (parser, missing)
2279 else
2280 with_type_parser parser TypeParser.parse_return_type
2282 (parser, colon, return_type)
2284 and parse_anon parser =
2285 (* SPEC
2286 anonymous-function-creation-expression:
2287 static-opt async-opt coroutine-opt function
2288 ( anonymous-function-parameter-list-opt )
2289 anonymous-function-return-opt
2290 anonymous-function-use-clauseopt
2291 compound-statement
2293 (* An anonymous function's formal parameter list is the same as a named
2294 function's formal parameter list except that types are optional.
2295 The "..." syntax and trailing commas are supported. We'll simply
2296 parse an optional parameter list; it already takes care of making the
2297 type annotations optional. *)
2298 let (parser, static) = optional_token parser Static in
2299 let (parser, async) = optional_token parser Async in
2300 let (parser, coroutine) = optional_token parser Coroutine in
2301 let (parser, fn) = assert_token parser Function in
2302 let (parser, left_paren, params, right_paren) =
2303 parse_parameter_list_opt parser in
2304 let (parser, colon, return_type, use_clause, is_php7) =
2305 let (parser, use_clause) = parse_anon_use_opt parser in
2306 if is_missing use_clause then begin
2307 let (parser, colon, return_type) = parse_optional_return parser in
2308 let (parser, use_clause) = parse_anon_use_opt parser in
2309 (parser, colon, return_type, use_clause, false)
2311 else begin
2312 (* might be PHP7 style lambda where return type follows use clause *)
2313 let (parser, colon, return_type) = parse_optional_return parser in
2314 (parser, colon, return_type, use_clause, not (is_missing colon))
2315 end in
2316 let (parser, body) = parse_compound_statement parser in
2317 let result =
2318 if is_php7
2319 then
2320 make_php7_anonymous_function
2321 static
2322 async
2323 coroutine
2325 left_paren
2326 params
2327 right_paren
2328 use_clause
2329 colon
2330 return_type
2331 body
2332 else
2333 make_anonymous_function
2334 static
2335 async
2336 coroutine
2338 left_paren
2339 params
2340 right_paren
2341 colon
2342 return_type
2343 use_clause
2344 body in
2345 (parser, result)
2347 and parse_braced_expression parser =
2348 let (parser, left_brace) = assert_token parser LeftBrace in
2349 let (parser, expression) = parse_expression_with_reset_precedence parser in
2350 let (parser, right_brace) = require_right_brace parser in
2351 let node = make_braced_expression left_brace expression right_brace in
2352 (parser, node)
2354 and require_right_brace_xhp parser =
2355 let (parser1, token) = next_xhp_body_token parser in
2356 if (Token.kind token) = TokenKind.RightBrace then
2357 (parser1, make_token token)
2358 else
2359 (* ERROR RECOVERY: Create a missing token for the expected token,
2360 and continue on from the current token. Don't skip it. *)
2361 let missing = make_missing parser in
2362 let parser = with_error parser SyntaxError.error1006 in
2363 (parser, missing)
2365 and parse_xhp_body_braced_expression parser =
2366 (* The difference between a regular braced expression and an
2367 XHP body braced expression is:
2368 <foo bar={$x}/*this_is_a_comment*/>{$y}/*this_is_body_text!*/</foo>
2370 let (parser, left_brace) = assert_token parser LeftBrace in
2371 let (parser, expression) = parse_expression_with_reset_precedence parser in
2372 let (parser, right_brace) = require_right_brace_xhp parser in
2373 let node = make_braced_expression left_brace expression right_brace in
2374 (parser, node)
2376 and parse_xhp_attribute parser =
2377 let (parser', token, _) = next_xhp_element_token parser in
2378 match (Token.kind token) with
2379 | LeftBrace -> parse_xhp_spread_attribute parser
2380 | XHPElementName -> parse_xhp_simple_attribute parser' (make_token token)
2381 | _ -> (parser, None)
2383 and parse_xhp_spread_attribute parser =
2384 let (parser, left_brace, _) = next_xhp_element_token parser in
2385 let (parser, ellipsis) = assert_token parser DotDotDot in
2386 let (parser, expression) = parse_expression_with_reset_precedence parser in
2387 let (parser, right_brace) = require_right_brace parser in
2388 let node = make_xhp_spread_attribute (make_token left_brace) ellipsis expression right_brace in
2389 (parser, Some node)
2391 and parse_xhp_simple_attribute parser name =
2392 (* Parse the attribute name and then defensively check for well-formed
2393 * attribute assignment *)
2394 let (parser', token, _) = next_xhp_element_token parser in
2395 if (Token.kind token) != Equal then
2396 let value = make_missing parser in
2397 let node = make_xhp_simple_attribute name (make_missing parser') value in
2398 let parser = with_error parser SyntaxError.error1016 in
2399 (* ERROR RECOVERY: The = is missing; assume that the name belongs
2400 to the attribute, but that the remainder is missing, and start
2401 looking for the next attribute. *)
2402 (parser, Some node)
2403 else
2404 let equal = make_token token in
2405 let (parser'', token, text) = next_xhp_element_token parser' in
2406 match (Token.kind token) with
2407 | XHPStringLiteral ->
2408 let node = make_xhp_simple_attribute name equal (make_token token) in
2409 (parser'', Some node)
2410 | LeftBrace ->
2411 let (parser, expr) = parse_braced_expression parser' in
2412 let node = make_xhp_simple_attribute name equal expr in
2413 (parser, Some node)
2414 | _ ->
2415 (* ERROR RECOVERY: The expression is missing; assume that the "name ="
2416 belongs to the attribute and start looking for the next attribute. *)
2417 let node = make_xhp_simple_attribute name equal (make_missing parser'') in
2418 let parser = with_error parser' SyntaxError.error1017 in
2419 (parser, Some node)
2421 and parse_xhp_body_element parser =
2422 let (parser1, token) = next_xhp_body_token parser in
2423 match Token.kind token with
2424 | XHPComment
2425 | XHPBody -> (parser1, Some (make_token token))
2426 | LeftBrace ->
2427 let (parser, expr) = parse_xhp_body_braced_expression parser in
2428 (parser, Some expr)
2429 | RightBrace ->
2430 (* If we find a free-floating right-brace in the middle of an XHP body
2431 that's just fine. It's part of the text. However, it is also likely
2432 to be a mis-edit, so we'll keep it as a right-brace token so that
2433 tooling can flag it as suspicious. *)
2434 (parser1, Some (make_token token))
2435 | LessThan ->
2436 let (parser, expr) =
2437 parse_possible_xhp_expression ~consume_trailing_trivia:false parser in
2438 (parser, Some expr)
2439 | _ -> (parser, None)
2441 and parse_xhp_close ~consume_trailing_trivia parser _ =
2442 let (parser1, less_than_slash, _) = next_xhp_element_token parser in
2443 if (Token.kind less_than_slash) = LessThanSlash then
2444 let (parser2, name, name_text) = next_xhp_element_token parser1 in
2445 if (Token.kind name) = XHPElementName then
2446 (* TODO: Check that the given and name_text are the same. *)
2447 let (parser3, greater_than, _) =
2448 next_xhp_element_token ~no_trailing:(not consume_trailing_trivia) parser2 in
2449 if (Token.kind greater_than) = GreaterThan then
2450 (parser3, make_xhp_close (make_token less_than_slash)
2451 (make_token name) (make_token greater_than))
2452 else
2453 (* ERROR RECOVERY: *)
2454 let parser = with_error parser2 SyntaxError.error1039 in
2455 let less_than_slash_token = make_token less_than_slash in
2456 let name_token = make_token name in
2457 let missing = make_missing parser in
2458 (parser, make_xhp_close less_than_slash_token name_token missing)
2459 else
2460 (* ERROR RECOVERY: *)
2461 let parser = with_error parser1 SyntaxError.error1039 in
2462 let less_than_slash_token = make_token less_than_slash in
2463 let missing1 = make_missing parser in
2464 let missing2 = make_missing parser in
2465 (parser, make_xhp_close less_than_slash_token missing1 missing2)
2466 else
2467 (* ERROR RECOVERY: We probably got a < without a following / or name.
2468 TODO: For now we'll just bail out. We could use a more
2469 sophisticated strategy here. *)
2470 let parser = with_error parser1 SyntaxError.error1026 in
2471 let less_than_slash_token = make_token less_than_slash in
2472 let missing1 = make_missing parser in
2473 let missing2 = make_missing parser in
2474 (parser, make_xhp_close less_than_slash_token missing1 missing2)
2476 and parse_xhp_expression ~consume_trailing_trivia parser left_angle name name_text =
2477 let (parser, attrs) = parse_list_until_none parser parse_xhp_attribute in
2478 let (parser1, token, _) = next_xhp_element_token ~no_trailing:true parser in
2479 match (Token.kind token) with
2480 | SlashGreaterThan ->
2481 let xhp_open = make_xhp_open left_angle name attrs (make_token token) in
2482 let missing1 = make_missing parser in
2483 let missing2 = make_missing parser in
2484 let xhp = make_xhp_expression xhp_open missing1 missing2 in
2485 (parser1, xhp)
2486 | GreaterThan ->
2487 let xhp_open = make_xhp_open left_angle name attrs (make_token token) in
2488 let (parser, xhp_body) =
2489 parse_list_until_none parser1 parse_xhp_body_element in
2490 let (parser, xhp_close) = parse_xhp_close ~consume_trailing_trivia parser name_text in
2491 let xhp = make_xhp_expression xhp_open xhp_body xhp_close in
2492 (parser, xhp)
2493 | _ ->
2494 (* ERROR RECOVERY: Assume the unexpected token belongs to whatever
2495 comes next. *)
2496 let missing = make_missing parser in
2497 let xhp_open = make_xhp_open left_angle name attrs missing in
2498 let missing1 = make_missing parser in
2499 let missing2 = make_missing parser in
2500 let xhp = make_xhp_expression xhp_open missing1 missing2 in
2501 let parser = with_error parser SyntaxError.error1013 in
2502 (parser, xhp)
2504 and parse_possible_xhp_expression ~consume_trailing_trivia parser =
2505 (* We got a < token where an expression was expected. *)
2506 let (parser, less_than) = assert_token parser LessThan in
2507 let (parser1, name, text) = next_xhp_element_token parser in
2508 if (Token.kind name) = XHPElementName then
2509 parse_xhp_expression
2510 ~consume_trailing_trivia parser1 less_than (make_token name) text
2511 else
2512 (* ERROR RECOVERY
2513 Hard to say what to do here. We are expecting an expression;
2514 we could simply produce an error for the < and call that the
2515 expression. Or we could assume the the left side of an inequality is
2516 missing, give a missing node for the left side, and parse the
2517 remainder as the right side. We'll go for the former for now. *)
2518 (with_error parser SyntaxError.error1015, less_than)
2520 and parse_anon_or_awaitable_or_scope_resolution_or_name parser =
2521 (* static is a legal identifier, if next token is scope resolution operatpr
2522 - parse expresson as scope resolution operator, otherwise try to interpret
2523 it as anonymous function (will fallback to name in case of failure) *)
2524 if peek_token_kind ~lookahead:1 parser = ColonColon then
2525 parse_scope_resolution_or_name parser
2526 else
2527 parse_anon_or_lambda_or_awaitable parser
2529 and parse_scope_resolution_or_name parser =
2530 (* parent, self and static are legal identifiers. If the next
2531 thing that follows is a scope resolution operator, parse them as
2532 ordinary tokens, and then we'll pick them up as the operand to the
2533 scope resolution operator when we call parse_remaining_expression.
2534 Otherwise, parse them as ordinary names. *)
2535 let (parser1, qualifier) = next_token parser in
2536 if peek_token_kind parser1 = ColonColon then
2537 (parser1, (make_token qualifier))
2538 else
2539 parse_as_name_or_error parser
2541 and parse_scope_resolution_expression parser qualifier =
2542 (* SPEC
2543 scope-resolution-expression:
2544 scope-resolution-qualifier :: name
2545 scope-resolution-qualifier :: class
2547 scope-resolution-qualifier:
2548 qualified-name
2549 variable-name
2550 self
2551 parent
2552 static
2554 (* TODO: The left hand side can in fact be any expression in this parser;
2555 we need to add a later error pass to detect that the left hand side is
2556 a valid qualifier. *)
2557 (* TODO: The right hand side, if a name or a variable, is treated as a
2558 name or variable *token* and not a name or variable *expression*. Is
2559 that the desired tree topology? Give this more thought; it might impact
2560 rename refactoring semantics. *)
2561 let (parser, op) = require_coloncolon parser in
2562 let (parser, name) =
2563 let parser1, token = next_token parser in
2564 match Token.kind token with
2565 | Class -> parser1, make_token token
2566 | Dollar -> parse_dollar_expression parser
2567 | LeftBrace -> parse_braced_expression parser
2568 | Variable when Env.php5_compat_mode (env parser) ->
2569 let parser1, e = parse_variable_in_php5_compat_mode parser in
2570 (* for :: only do PHP5 transform for call expressions
2571 in other cases fall back to the regular parsing logic *)
2572 if peek_token_kind parser1 = LeftParen &&
2573 (* make sure the left parenthesis means a call
2574 for the expression we are currently parsing, and
2575 are not for example for a constructor call whose
2576 name would be the result of this expression. *)
2577 not @@ operator_has_lower_precedence LeftParen parser
2578 then parser1, e
2579 else require_name_or_variable_or_error parser SyntaxError.error1048
2580 | _ ->
2581 require_name_or_variable_or_error parser SyntaxError.error1048
2583 let result = make_scope_resolution_expression qualifier op name in
2584 (parser, result)
2586 end (* WithSmartConstructors *)
2587 end (* WithSyntax *)