2 * Copyright (c) 2016, Facebook, Inc.
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.
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
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
29 .WithLexer
(Full_fidelity_lexer.WithToken
(Syntax.Token
))
32 module type DeclarationParser_S
= Full_fidelity_declaration_parser_type
34 .WithLexer
(Full_fidelity_lexer.WithToken
(Syntax.Token
))
37 module type TypeParser_S
= Full_fidelity_type_parser_type
39 .WithLexer
(Full_fidelity_lexer.WithToken
(Syntax.Token
))
42 module type ExpressionParser_S
= Full_fidelity_expression_parser_type
44 .WithLexer
(Full_fidelity_lexer.WithToken
(Syntax.Token
))
47 module ParserHelperSyntax
= Full_fidelity_parser_helpers.WithSyntax
(Syntax
)
49 ParserHelperSyntax.WithLexer
(Full_fidelity_lexer.WithToken
(Syntax.Token
))
51 module WithSmartConstructors
(SCI
: SCWithKind_S
with module Token
= Syntax.Token
)
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
)
64 module Parser
= PrecedenceParser.WithSmartConstructors
(SCI
)
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
85 let with_type_parser : 'a
. t
-> (TypeParser.t
-> TypeParser.t
* 'a
) -> t
* 'a
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
104 let parse_generic_type_arguments_opt parser =
105 with_type_parser parser
107 let (p
, items
, no_arg_is_missing
) =
108 TypeParser.parse_generic_type_argument_list_opt p
110 (p
, (items
, no_arg_is_missing
))
113 let with_decl_parser : 'a
. t
-> (DeclParser.t
-> DeclParser.t
* 'a
) -> t
* 'a
123 let (decl_parser, node) = f
decl_parser in
124 let env = DeclParser.env decl_parser in
125 let lexer = DeclParser.lexer decl_parser in
126 let errors = DeclParser.errors decl_parser in
127 let context = DeclParser.context decl_parser in
128 let sc_state = DeclParser.sc_state decl_parser in
129 let parser = { parser with env; lexer; errors; context; sc_state } in
132 let parse_compound_statement parser =
133 let statement_parser =
141 let (statement_parser, statement
) =
142 StatementParser.parse_compound_statement statement_parser in
143 let env = StatementParser.env statement_parser in
144 let lexer = StatementParser.lexer statement_parser in
145 let errors = StatementParser.errors statement_parser in
146 let context = StatementParser.context statement_parser in
147 let sc_state = StatementParser.sc_state statement_parser in
148 let parser = { parser with env; lexer; errors; context; sc_state } in
151 let parse_parameter_list_opt parser =
152 let (parser, (left
, token
, right
)) = with_decl_parser parser
154 let (parser, left
, token
, right
) =
155 DeclParser.parse_parameter_list_opt decl_parser
157 parser, (left
, token
, right
)
160 (parser, left
, token
, right
)
162 let rec parse_expression parser =
163 let (parser, term
) = parse_term
parser in
164 parse_remaining_expression
parser term
166 and parse_expression_with_reset_precedence
parser =
167 with_reset_precedence
parser parse_expression
169 and parse_expression_with_operator_precedence
parser operator
=
170 with_operator_precedence
parser operator
parse_expression
172 and parse_if_no_error
parser f
=
173 let old_errors = List.length
(errors parser) in
175 let (parser, result
) = f
parser in
176 let new_errors = List.length
(errors parser) in
177 Option.some_if
(old_errors = new_errors) (parser, result
)
178 with Failure _
-> None
180 and parse_as_name_or_error
parser =
181 (* TODO: Are there "reserved" keywords that absolutely cannot start
182 an expression? If so, list them above and make them produce an
184 let (parser1
, token
) = next_token_as_name
parser in
185 match (Token.kind token
) with
187 let (parser1
, name
) =
188 scan_remaining_qualified_name parser1
(make_token token
) in
189 parse_name_or_collection_literal_expression parser1 name
190 | kind
when Parser.expects_here
parser kind
->
191 (* ERROR RECOVERY: If we're encountering a token that matches a kind in
192 * the previous scope of the expected stack, don't eat it--just mark the
193 * name missing and continue parsing, starting from the offending token. *)
194 let missing = make_missing
parser in
195 let parser = with_error
parser SyntaxError.error1015
in
198 (* ERROR RECOVERY: If we're encountering anything other than a Name
199 * or the next expected kind, eat the offending token.
200 * TODO: Increase the coverage of PrecedenceParser.expects_next, so that
201 * we wind up eating fewer of the tokens that'll be needed by the outer
202 * statement / declaration parsers. *)
203 let parser = with_error parser1
SyntaxError.error1015
in
204 (parser, make_token token
)
206 and parse_term
parser =
207 let (parser1
, token
) = next_xhp_class_name_or_other_token
parser in
208 match (Token.kind token
) with
209 (* TODO: Make these an error in Hack *)
210 | ExecutionStringLiteral
216 | SingleQuotedStringLiteral
217 | NowdocStringLiteral
218 | DoubleQuotedStringLiteral
220 | NullLiteral
-> (parser1
, make_literal_expression
(make_token token
))
221 | HeredocStringLiteral
->
222 (* We have a heredoc string literal but it might contain embedded
223 expressions. Start over. *)
224 let (parser, token
, name
) = next_docstring_header
parser in
225 parse_heredoc_string
parser token name
226 | HeredocStringLiteralHead
227 | DoubleQuotedStringLiteralHead
->
228 parse_double_quoted_like_string
229 parser1 token
Lexer.Literal_double_quoted
230 | ExecutionStringLiteralHead
->
231 parse_double_quoted_like_string
232 parser1 token
Lexer.Literal_execution_string
233 | Variable
-> parse_variable_or_lambda
parser
235 parse_name_or_collection_literal_expression parser1
(make_token token
)
237 let (parser1
, qualified_name
) =
238 scan_remaining_qualified_name parser1
(make_token token
) in
239 parse_name_or_collection_literal_expression parser1 qualified_name
241 let (parser1
, qualified_name
) =
242 scan_qualified_name parser1
(make_token token
) in
243 parse_name_or_collection_literal_expression parser1 qualified_name
245 | Parent
-> parse_scope_resolution_or_name
parser
247 parse_anon_or_awaitable_or_scope_resolution_or_name
parser
248 | Yield
-> parse_yield_expression
parser
249 | Dollar
-> parse_dollar_expression
parser
251 (* TODO: The operand to a suspend is required to be a call to a
252 coroutine. Give an error in a later pass if this isn't the case. *)
263 | At
-> parse_prefix_unary_expression
parser
264 | LeftParen
-> parse_cast_or_parenthesized_or_lambda_expression
parser
265 | LessThan
-> parse_possible_xhp_expression ~consume_trailing_trivia
:true parser
266 | List
-> parse_list_expression
parser
267 | New
-> parse_object_creation_expression
parser
268 | Array
-> parse_array_intrinsic_expression
parser
269 | Varray
-> parse_varray_intrinsic_expression
parser
270 | Vec
-> parse_vector_intrinsic_expression
parser
271 | Darray
-> parse_darray_intrinsic_expression
parser
272 | Dict
-> parse_dictionary_intrinsic_expression
parser
273 | Keyset
-> parse_keyset_intrinsic_expression
parser
274 | LeftBracket
-> parse_array_creation_expression
parser
275 | Tuple
-> parse_tuple_expression
parser
276 | Shape
-> parse_shape_expression
parser
277 | Function
-> parse_anon
parser
279 (parser1
, make_pipe_variable_expression
(make_token token
))
281 | Coroutine
-> parse_anon_or_lambda_or_awaitable
parser
285 | Require_once
-> parse_inclusion_expression
parser
286 | Empty
-> parse_empty_expression
parser
287 | Isset
-> parse_isset_expression
parser
288 | Define
-> parse_define_expression
parser
289 | HaltCompiler
-> parse_halt_compiler_expression
parser
290 | Eval
-> parse_eval_expression
parser
291 | kind
when Parser.expects
parser kind
->
292 (* ERROR RECOVERY: if we've prematurely found a token we're expecting
293 * later, mark the expression missing, throw an error, and do not advance
295 let missing = make_missing
parser in
296 let parser = with_error
parser SyntaxError.error1015
in
298 | TokenKind.EndOfFile
299 | _
-> parse_as_name_or_error
parser
301 and parse_empty_expression
parser =
302 (* TODO: This is a PHP-ism. Open questions:
303 * Should we allow a trailing comma? it is not a function call and
304 never has more than one argument. See D4273242 for discussion.
305 * Is there any restriction on the kind of expression this can be?
306 * Should this be an error in strict mode?
307 * Should this be in the specification?
308 * Empty is case-insensitive; should use of non-lowercase be an error?
310 (* TODO: The original Hack and HHVM parsers accept "empty" as an
311 identifier, so we do too; consider whether it should be reserved. *)
312 let (parser1
, keyword
) = assert_token
parser Empty
in
313 if peek_token_kind parser1
= LeftParen
then
314 let (parser, left
) = assert_token parser1 LeftParen
in
315 let (parser, arg
) = parse_expression_with_reset_precedence
parser in
316 let (parser, right
) = require_right_paren
parser in
317 let result = make_empty_expression keyword left arg right
in
320 parse_as_name_or_error
parser
322 and parse_eval_expression
parser =
323 (* TODO: This is a PHP-ism. Open questions:
324 * Should we allow a trailing comma? it is not a function call and
325 never has more than one argument. See D4273242 for discussion.
326 * Is there any restriction on the kind of expression this can be?
327 * Should this be an error in strict mode?
328 * Should this be in the specification?
329 * Eval is case-insensitive. Should use of non-lowercase be an error?
331 (* TODO: The original Hack and HHVM parsers accept "eval" as an
332 identifier, so we do too; consider whether it should be reserved. *)
333 let (parser1
, keyword
) = assert_token
parser Eval
in
334 if peek_token_kind parser1
= LeftParen
then
335 let (parser, left
) = assert_token parser1 LeftParen
in
336 let (parser, arg
) = parse_expression_with_reset_precedence
parser in
337 let (parser, right
) = require_right_paren
parser in
338 let result = make_eval_expression keyword left arg right
in
341 parse_as_name_or_error
parser
343 and parse_isset_expression
parser =
344 (* TODO: This is a PHP-ism. Open questions:
345 * Should we allow a trailing comma? See D4273242 for discussion.
346 * Is there any restriction on the kind of expression the arguments can be?
347 * Should this be an error in strict mode?
348 * Should this be in the specification?
349 * PHP requires that there be at least one argument; should we require
350 that? if so, should we give the error in the parser or a later pass?
351 * Isset is case-insensitive. Should use of non-lowercase be an error?
353 (* TODO: The original Hack and HHVM parsers accept "isset" as an
354 identifier, so we do too; consider whether it should be reserved. *)
356 let (parser1
, keyword
) = assert_token
parser Isset
in
357 if peek_token_kind parser1
= LeftParen
then
358 let (parser, left
, args
, right
) = parse_expression_list_opt parser1
in
359 let result = make_isset_expression keyword left args right
in
362 parse_as_name_or_error
parser
364 and parse_define_expression
parser =
365 (* TODO: This is a PHP-ism. Open questions:
366 * Should we allow a trailing comma? See D4273242 for discussion.
367 * Is there any restriction on the kind of expression the arguments can be?
368 They must be string, value, bool, but do they have to be compile-time
369 constants, for instance?
370 * Should this be an error in strict mode? You should use const instead.
371 * Should this be in the specification?
372 * PHP requires that there be at least two arguments; should we require
373 that? if so, should we give the error in the parser or a later pass?
374 * is define case-insensitive?
376 (* TODO: The original Hack and HHVM parsers accept "define" as an
377 identifier, so we do too; consider whether it should be reserved. *)
378 let (parser1
, keyword
) = assert_token
parser Define
in
379 if peek_token_kind parser1
= LeftParen
then
380 let (parser, left
, args
, right
) = parse_expression_list_opt parser1
in
381 let result = make_define_expression keyword left args right
in
384 parse_as_name_or_error
parser
386 and parse_halt_compiler_expression
parser =
387 let (parser1
, keyword
) = assert_token
parser HaltCompiler
in
388 if peek_token_kind parser1
= LeftParen
then
389 let (parser, left
, args
, right
) = parse_expression_list_opt parser1
in
390 parser, make_halt_compiler_expression keyword left args right
392 let parser = with_error
parser SyntaxError.error1019
in
393 parse_as_name_or_error
parser
395 and parse_double_quoted_like_string
parser head literal_kind
=
396 parse_string_literal
parser head literal_kind
398 and parse_heredoc_string
parser head name
=
399 parse_string_literal
parser head
(Lexer.Literal_heredoc name
)
401 and parse_braced_expression_in_string
parser =
403 We are parsing something like "abc{$x}def" or "abc${x}def", and we
404 are at the left brace.
406 We know that the left brace will not be preceded by trivia. However in the
407 second of the two cases mentioned above it is legal for there to be trivia
408 following the left brace. If we are in the first case, we've already
409 verified that there is no trailing trivia after the left brace.
411 The expression may be followed by arbitrary trivia, including
412 newlines and comments. That means that the closing brace may have
413 leading trivia. But under no circumstances does the closing brace have
416 It's an error for the closing brace to be missing.
418 Therefore we lex the left brace normally, parse the expression normally,
419 but require that there be a right brace. We do not lex the trailing trivia
422 ERROR RECOVERY: If the right brace is missing, treat the remainder as
425 let (parser, left_brace
) = assert_token
parser LeftBrace
in
426 let (parser1
, name_or_keyword_as_name
) = next_token_as_name
parser in
427 let (parser1
, right_brace
) = next_token_no_trailing parser1
in
428 let (parser, expr
, right_brace
) =
429 match Token.kind name_or_keyword_as_name
, Token.kind right_brace
with
430 | Name
, RightBrace
->
431 let expr = make_token name_or_keyword_as_name
in
432 let right_brace = make_token
right_brace in
433 parser1
, expr, right_brace
435 let (parser, expr) = parse_expression_with_reset_precedence
parser in
436 let (parser1
, token
) = next_token_no_trailing
parser in
437 let (parser, right_brace) =
438 if (Token.kind token
) = RightBrace
then
439 (parser1
, make_token token
)
441 let missing = make_missing
parser in
442 let parser = with_error
parser SyntaxError.error1006
in
445 parser, expr, right_brace
447 let node = make_embedded_braced_expression left_brace
expr right_brace in
450 and parse_string_literal
parser head literal_kind
=
453 Double-quoted string literals and heredoc string literals use basically
454 the same rules; here we have just the grammar for double-quoted string
458 variable-name offset-or-property-opt
474 The actual situation is considerably more complex than indicated
475 in the specification.
477 TODO: Consider updating the specification.
479 * The tokens in the grammar above have no leading or trailing trivia.
481 * An embedded variable expression may also be enclosed in curly braces;
482 however, the $ of the variable expression must follow immediately after
485 * An embedded variable expression inside braces allows trivia between
486 the tokens and before the right brace.
488 * An embedded variable expression inside braces can be a much more complex
489 expression than indicated by the grammar above. For example,
490 {$c->x->y[0]} is good, and {$c[$x instanceof foo ? 0 : 1]} is good,
491 but {$c instanceof foo ? $x : $y} is not. It is not clear to me what
492 the legal grammar here is; it seems best in this situation to simply
493 parse any expression and do an error pass later.
495 * Note that the braced expressions can include double-quoted strings.
496 {$c["abc"]} is good, for instance.
498 * ${ is illegal in strict mode. In non-strict mode, ${varname is treated
499 the same as {$varname, and may be an arbitrary expression.
501 * TODO: We need to produce errors if there are unbalanced brackets,
502 example: "$x[0" is illegal.
504 * TODO: Similarly for any non-valid thing following the left bracket,
505 including trivia. example: "$x[ 0]" is illegal.
509 let merge token
= function
510 (* TODO: Assert that new head has no leading trivia, old head has no
512 (* Invariant: A token inside a list of string fragments is always a head,
514 (* TODO: Is this invariant what we want? We could preserve the parse of
515 the string. That is, something like "a${b}c${d}e" is at present
516 represented as head, expr, body, expr, tail. It could be instead
517 head, dollar, left brace, expr, right brace, body, dollar, left
518 brace, expr, right brace, tail. Is that better?
520 TODO: Similarly we might want to preserve the structure of
521 heredoc strings in the parse: that there is a header consisting of
522 an identifier, and so on, and then body text, etc. *)
524 let k = match (Token.kind head
, Token.kind token
) with
525 | (DoubleQuotedStringLiteralHead
, DoubleQuotedStringLiteralTail
) ->
526 DoubleQuotedStringLiteral
527 | (ExecutionStringLiteralHead
, ExecutionStringLiteralTail
) ->
528 ExecutionStringLiteral
529 | (HeredocStringLiteralHead
, HeredocStringLiteralTail
) ->
531 | (DoubleQuotedStringLiteralHead
, _
) ->
532 DoubleQuotedStringLiteralHead
533 | (ExecutionStringLiteralHead
, _
) ->
534 ExecutionStringLiteralHead
535 | (HeredocStringLiteralHead
, _
) ->
536 HeredocStringLiteralHead
537 | (_
, DoubleQuotedStringLiteralTail
) ->
538 DoubleQuotedStringLiteralTail
539 | (_
, HeredocStringLiteralTail
) ->
540 HeredocStringLiteralTail
541 | (_
, ExecutionStringLiteralTail
) ->
542 ExecutionStringLiteralTail
546 let s = Token.source_text head
in
547 let o = Token.leading_start_offset head
in
548 let w = (Token.width head
) + (Token.width token
) in
549 let l = Token.leading head
in
550 let t = Token.trailing token
in
551 (* TODO: Make a "position" type that is a tuple of source and offset. *)
552 Some
(Token.make
k s o w l t)
554 let token = match Token.kind
token with
556 | HeredocStringLiteralTail
557 | DoubleQuotedStringLiteralTail
558 | ExecutionStringLiteralTail
->
561 Token.with_kind
token StringLiteralBody
566 let put_opt head acc
=
567 Option.value_map ~default
:acc ~f
:(fun h
-> make_token h
:: acc
) head
570 let parse_embedded_expression parser token =
571 let var_expr = make_variable_expression
(make_token
token) in
572 let (parser1
, token1
) = next_token_in_string
parser literal_kind
in
573 let (parser2
, token2
) = next_token_in_string parser1 literal_kind
in
574 let (parser3
, token3
) = next_token_in_string parser2 literal_kind
in
575 match (Token.kind token1
, Token.kind token2
, Token.kind token3
) with
576 | (MinusGreaterThan
, Name
, _
) ->
577 let expr = make_embedded_member_selection_expression
var_expr
578 (make_token token1
) (make_token token2
) in
580 | (LeftBracket
, Name
, RightBracket
) ->
581 let expr = make_embedded_subscript_expression
var_expr
584 (make_token token3
) in
586 | (LeftBracket
, Variable
, RightBracket
) ->
587 let expr = make_embedded_subscript_expression
var_expr
588 (make_token token1
) (make_variable_expression
(make_token token2
))
589 (make_token token3
) in
591 | (LeftBracket
, DecimalLiteral
, RightBracket
)
592 | (LeftBracket
, OctalLiteral
, RightBracket
)
593 | (LeftBracket
, HexadecimalLiteral
, RightBracket
)
594 | (LeftBracket
, BinaryLiteral
, RightBracket
) ->
595 let expr = make_embedded_subscript_expression
var_expr
596 (make_token token1
) (make_literal_expression
(make_token token2
))
597 (make_token token3
) in
599 | _
-> (parser, var_expr)
602 let rec handle_left_brace parser head acc
=
603 (* Note that here we use next_token_in_string because we need to know
604 whether there is trivia between the left brace and the $x which follows.*)
605 let (parser1
, left_brace
) = next_token_in_string
parser literal_kind
in
606 let (_
, token) = next_token_in_string parser1 literal_kind
in
607 (* TODO: What about "{$$}" ? *)
608 match Token.kind
token with
610 (* Parse any expression followed by a close brace.
611 TODO: We do not actually support all possible expressions;
612 see above. Do we want to (1) catch this at parse time,
613 (2) catch it in a later pass, or (3) just allow any
615 let (parser, expr) = parse_braced_expression_in_string
parser in
616 aux
parser None
(expr :: (put_opt head acc
))
618 (* We do not support {$ inside a string unless the $ begins a
619 variable name. Append the { and start again on the $. *)
620 (* TODO: Is this right? Suppose we have "{${x}". Is that the same
621 as "{"."${x}" ? Double check this. *)
622 (* TODO: Give an error. *)
623 (* We got a { not followed by a $. Ignore it. *)
624 (* TODO: Give a warning? *)
625 aux parser1
(merge left_brace head
) acc
627 and handle_dollar
parser dollar head acc
=
628 (* We need to parse ${x} as though it was {$x} *)
629 (* TODO: This should be an error in strict mode. *)
630 (* We must not have trivia between the $ and the {, but we can have
631 trivia after the {. That's why we use next_token_in_string here. *)
632 let (_
, token) = next_token_in_string
parser literal_kind
in
633 match Token.kind
token with
635 (* The thing in the braces has to be an expression that begins
636 with a variable, and the variable does *not* begin with a $. It's
639 Unlike the {$var} case, there *can* be trivia before the expression,
640 which means that trivia is likely the trailing trivia of the brace,
641 not leading trivia of the expression. *)
642 (* TODO: Enforce these rules by producing an error if they are
644 (* TODO: Make the parse tree for the leading word in the expression
645 a variable expression, not a qualified name expression. *)
647 let (parser, expr) = parse_braced_expression_in_string
parser in
648 aux
parser None
(expr :: (make_token dollar
) :: (put_opt head acc
))
650 (* We got a $ not followed by a { or variable name. Ignore it. *)
651 (* TODO: Give a warning? *)
652 aux
parser (merge dollar head
) acc
654 and aux
parser head acc
=
655 let (parser1
, token) = next_token_in_string
parser literal_kind
in
656 match Token.kind
token with
657 | HeredocStringLiteralTail
658 | DoubleQuotedStringLiteralTail
659 | ExecutionStringLiteralTail
->
660 parser1
, (put_opt (merge token head
) acc
)
662 handle_left_brace parser head acc
664 let (parser, expr) = parse_embedded_expression parser1
token in
665 aux
parser None
(expr :: (put_opt head acc
))
667 handle_dollar parser1
token head acc
669 aux parser1
(merge token head
) acc
672 let (parser, results
) = aux
parser (Some head
) [] in
673 (* If we've ended up with a single string literal with no internal
674 structure, do not represent that as a list with one item. *)
675 let results = match results with
677 | _
-> make_list
parser (List.rev
results) in
678 let result = make_literal_expression
results in
681 and parse_inclusion_expression
parser =
684 require-multiple-directive
685 require-once-directive
687 require-multiple-directive:
688 require include-filename ;
693 require-once-directive:
694 require_once include-filename ;
696 In non-strict mode we allow an inclusion directive (without semi) to be
697 used as an expression. It is therefore easier to actually parse this as:
700 inclusion-expression ;
702 inclusion-expression:
703 require include-filename
704 require_once include-filename
706 TODO: We allow "include" and "include_once" as well, which are PHP-isms
707 specified as not supported in Hack. Do we need to produce an error in
710 TODO: Produce an error if this is used in an expression context
714 let (parser, require
) = next_token
parser in
715 let operator = Operator.prefix_unary_from_token
(Token.kind require
) in
716 let require = make_token
require in
717 let (parser, filename
) = parse_expression_with_operator_precedence
719 let result = make_inclusion_expression
require filename
in
722 and peek_next_kind_if_operator
parser =
723 let kind = peek_token_kind
parser in
724 if Operator.is_trailing_operator_token
kind then
729 and operator_has_lower_precedence operator_kind
parser =
730 let operator = Operator.trailing_from_token operator_kind
in
731 (Operator.precedence
operator) < parser.precedence
733 and next_is_lower_precedence
parser =
734 match peek_next_kind_if_operator
parser with
736 | Some
kind -> operator_has_lower_precedence
kind parser
738 and parse_remaining_expression_or_specified_function_call
parser term
740 let (parser1
, (type_arguments
, no_arg_is_missing
)) =
741 parse_generic_type_arguments_opt parser
744 && is_type_arguments type_arguments
745 && parser.errors = parser1
.errors
748 begin match peek_token_kind parser1
with
750 (* handle a<type-args>::... case *)
752 make_generic_type_specifier term type_arguments
in
753 parse_scope_resolution_expression parser1
type_specifier
755 let (parser, left
, args
, right
) = parse_expression_list_opt parser1
in
756 parser, make_function_call_with_type_arguments_expression
757 term type_arguments left args right
759 parse_remaining_expression
parser result
761 parse_remaining_binary_expression
parser term prefix_kind
763 (* Checks if given expression is a PHP variable.
765 https://github.com/php/php-langspec/blob/master/spec/10-expressions.md#grammar-variable
766 A variable is an expression that can in principle be used as an lvalue *)
767 and can_be_used_as_lvalue
parser t =
768 if is_variable_expression
t
769 || is_subscript_expression
t
770 || is_member_selection_expression
t
771 || is_scope_resolution_expression
t
773 else prefix_unary_expression_checker_helper
parser t Dollar
775 (* Checks if given node is prefix unary expression and verifies operator kind.
776 Recursively run can_be_used_as_lvalue *)
777 and prefix_unary_expression_checker_helper
parser t kind =
778 match find_in_prefix_unary_expression_stack parser t with
779 | Some
{ operator_kind
; operand
; _
} ->
780 if operator_kind
= kind then
781 can_be_used_as_lvalue
parser operand
786 (* checks if expression is a valid right hand side in by-ref assignment
787 which is '&'PHP variable *)
788 and is_byref_assignment_source
parser t =
789 prefix_unary_expression_checker_helper
parser t Ampersand
791 (*detects if left_term and operator can be treated as a beginning of
792 assignment (respecting the precedence of operator on the left of
794 - Prefix_none - either operator is not one of assignment operators or
795 precedence of the operator on the left is higher than precedence of
797 - Prefix_assignment - left_term and operator can be interpreted as a
799 - Prefix_byref_assignment - left_term and operator can be interpreted as a
800 prefix of byref assignment.*)
801 and check_if_parsable_as_assignment
parser left_term
operator left_precedence
803 (* in PHP precedence of assignment in expression is bumped up to
804 recognize cases like !$x = ... or $a == $b || $c = ...
805 which should be parsed as !($x = ...) and $a == $b || ($c = ...)
807 if left_precedence
>= Operator.precedence_for_assignment_in_expressions
then
809 else match operator with
810 | Equal
when can_be_used_as_lvalue
parser left_term
->
811 Prefix_byref_assignment
812 | Equal
when is_list_expression left_term
-> Prefix_assignment
813 | PlusEqual
| MinusEqual
| StarEqual
| SlashEqual
|
814 StarStarEqual
| DotEqual
| PercentEqual
| AmpersandEqual
|
815 BarEqual
| CaratEqual
| LessThanLessThanEqual
|
816 GreaterThanGreaterThanEqual
817 when can_be_used_as_lvalue
parser left_term
->
821 and can_term_take_type_args term
=
823 || is_qualified_name term
824 || is_member_selection_expression term
825 || is_safe_member_selection_expression term
826 || is_scope_resolution_expression term
828 and parse_remaining_expression
parser term
=
829 match peek_next_kind_if_operator
parser with
830 | None
-> (parser, term
)
832 let assignment_prefix_kind =
833 check_if_parsable_as_assignment
parser term
token parser.precedence
835 (* stop parsing expression if:
836 - precedence of the operator is less than precedence of the operator
839 - <term> <operator> does not look like a prefix of
840 some assignment expression*)
841 if operator_has_lower_precedence
token parser &&
842 assignment_prefix_kind = Prefix_none
then (parser, term
)
843 else match token with
844 (* Binary operators *)
845 (* TODO Add an error if PHP and / or / xor are used in Hack. *)
846 (* TODO Add an error if PHP style <> is used in Hack. *)
847 | LessThan
when can_term_take_type_args term
->
848 parse_remaining_expression_or_specified_function_call
parser term
849 assignment_prefix_kind
869 | LessThanLessThanEqual
870 | GreaterThanGreaterThanEqual
880 | LessThanGreaterThan
881 | ExclamationEqualEqual
883 | LessThanEqualGreaterThan
888 | GreaterThanGreaterThan
891 | QuestionQuestion
->
892 parse_remaining_binary_expression
parser term
assignment_prefix_kind
894 parse_instanceof_expression
parser term
896 parse_is_expression
parser term
897 | QuestionMinusGreaterThan
898 | MinusGreaterThan
->
899 let (parser, result) = parse_member_selection_expression
parser term
in
900 parse_remaining_expression
parser result
902 let (parser, result) = parse_scope_resolution_expression
parser term
in
903 parse_remaining_expression
parser result
905 | MinusMinus
-> parse_postfix_unary
parser term
906 | LeftParen
-> parse_function_call
parser term
908 | LeftBrace
-> parse_subscript
parser term
910 let (parser, token) = assert_token
parser Question
in
911 let (parser, result) = parse_conditional_expression
parser term
token in
912 parse_remaining_expression
parser result
914 parse_remaining_binary_expression
parser term
assignment_prefix_kind
915 | _
-> (parser, term
)
917 and parse_member_selection_expression
parser term
=
919 member-selection-expression:
920 postfix-expression -> name
921 postfix-expression -> variable-name
922 postfix-expression -> xhp-class-name (DRAFT XHP SPEC)
924 null-safe-member-selection-expression:
925 postfix-expression ?-> name
926 postfix-expression ?-> variable-name
927 postfix-expression ?-> xhp-class-name (DRAFT XHP SPEC)
929 PHP allows $a->{$b}; to be more compatible with PHP, and give
930 good errors, we allow that here as well.
932 TODO: Produce an error if the braced syntax is used in Hack.
935 let (parser, token) = next_token
parser in
936 let op = make_token
token in
937 (* TODO: We are putting the name / variable into the tree as a token
938 leaf, rather than as a name or variable expression. Is that right? *)
940 match peek_token_kind
parser with
942 parse_braced_expression
parser
943 | Variable
when Env.php5_compat_mode
(env parser) ->
944 parse_variable_in_php5_compat_mode
parser
946 parse_dollar_expression
parser
948 require_xhp_class_name_or_name_or_variable
parser in
949 let result = if (Token.kind token) = MinusGreaterThan
then
950 make_member_selection_expression term
op name
952 make_safe_member_selection_expression term
op name
in
955 and parse_variable_in_php5_compat_mode
parser =
956 (* PHP7 had a breaking change in parsing variables:
957 (https://wiki.php.net/rfc/uniform_variable_syntax).
958 Hack parser by default uses PHP7 compatible more which interprets
959 variables accesses left-to-right. It usually matches PHP5 behavior
960 except for cases with '$' operator, member accesses and scope resolution
962 $$a[1][2] -> ($$a)[1][2]
963 $a->$b[c] -> ($a->$b)[c]
964 X::$a[b]() -> (X::$a)[b]()
966 In order to preserve backward compatibility we can parse
967 variable/subscript expressions and treat them as if
968 braced expressions to enfore PHP5 semantics
969 $$a[1][2] -> ${$a[1][2]}
970 $a->$b[c] -> $a->{$b[c]}
971 X::$a[b]() -> X::{$a[b]}()
974 let precedence = Operator.precedence Operator.IndexingOperator
in
975 parse_expression (with_precedence
parser precedence) in
976 let parser1 = with_precedence
parser1 parser.precedence in
979 and parse_subscript
parser term
=
981 subscript-expression:
982 postfix-expression [ expression-opt ]
983 postfix-expression { expression-opt } [Deprecated form]
985 (* TODO: Produce an error for brace case in a later pass *)
986 let (parser, left
) = next_token
parser in
987 let (parser1, right
) = next_token
parser in
988 match (Token.kind left
, Token.kind right
) with
989 | (LeftBracket
, RightBracket
)
990 | (LeftBrace
, RightBrace
) ->
991 let left = make_token
left in
992 let index = make_missing
parser in
993 let right = make_token
right in
994 let result = make_subscript_expression term
left index right in
995 parse_remaining_expression
parser1 result
998 let (parser, index) = with_reset_precedence
parser parse_expression in
999 let (parser, right) = match Token.kind left with
1000 | LeftBracket
-> require_right_bracket
parser
1001 | _
-> require_right_brace
parser in
1002 let left = make_token
left in
1003 let result = make_subscript_expression term
left index right in
1004 parse_remaining_expression
parser result
1007 and parse_expression_list_opt
parser =
1010 TODO: This business of allowing ... does not appear in the spec. Add it.
1012 TODO: Add call-convention-opt to the specification.
1013 (This work is tracked by task T22582676.)
1015 TODO: Update grammar for inout parameters.
1016 (This work is tracked by task T22582715.)
1018 ERROR RECOVERY: A ... expression can only appear at the end of a
1019 formal parameter list. However, we parse it everywhere without error,
1020 and detect the error in a later pass.
1022 Note that it *is* legal for a ... expression be followed by a trailing
1023 comma, even though it is not legal for such in a formal parameter list.
1025 TODO: Can *any* expression appear after the ... ?
1027 argument-expression-list:
1028 argument-expressions ,-opt
1029 argument-expressions:
1032 call-convention-opt expression
1033 argument-expressions , expression
1035 (* This function parses the parens as well. *)
1037 with_reset_precedence
parser parse_decorated_expression_opt
in
1038 parse_parenthesized_comma_list_opt_allow_trailing
parser f
1040 and parse_decorated_expression_opt
parser =
1041 match peek_token_kind
parser with
1044 let (parser, decorator
) = next_token
parser in
1045 let (parser, expr) = parse_expression parser in
1046 let decorator = make_token
decorator in
1047 parser, make_decorated_expression
decorator expr
1048 | _
-> parse_expression parser
1050 and parse_start_of_type_specifier
parser start_token
=
1051 let (parser, name
) =
1052 if Token.kind start_token
= Backslash
1053 then scan_qualified_name
parser (make_token start_token
)
1054 else scan_remaining_qualified_name
parser (make_token start_token
) in
1055 match peek_token_kind
parser with
1056 | LeftParen
| LessThan
-> Some
(parser, name
)
1059 and parse_designator
parser =
1061 class-type-designator:
1065 member-selection-expression
1066 null-safe-member-selection-expression
1068 scope-resolution-expression
1069 subscript-expression
1072 TODO: Update the spec to allow qualified-name < type arguments >
1073 TODO: This will need to be fixed to allow situations where the qualified name
1074 is also a non-reserved token.
1076 let default parser =
1077 parse_expression_with_operator_precedence
parser Operator.NewOperator
in
1078 let (parser1, token) = next_token
parser in
1079 match Token.kind token with
1082 begin match peek_token_kind
parser1 with
1083 | LeftParen
-> (parser1, make_token
token)
1085 let (parser1, (type_arguments
, no_arg_is_missing
)) =
1086 parse_generic_type_arguments_opt parser1
1088 if no_arg_is_missing
1089 && is_type_arguments type_arguments
1090 && parser.errors = parser1.errors
1092 let type_specifier =
1093 make_generic_type_specifier
(make_token
token) type_arguments
in
1094 parser1, type_specifier
1100 | Static
when peek_token_kind
parser1 = LeftParen
->
1101 (parser1, make_token
token)
1104 begin match parse_start_of_type_specifier
parser1 token with
1105 | Some
(parser, name
) ->
1106 (* We want to parse new C() and new C<int>() as types, but
1107 new C::$x() as an expression. *)
1108 with_type_parser parser (TypeParser.parse_remaining_type_specifier name
)
1114 (* TODO: We need to verify in a later pass that the expression is a
1115 scope resolution (that does not end in class!), a member selection,
1116 a name, a variable, a property, or an array subscript expression. *)
1118 and parse_object_creation_expression
parser =
1120 object-creation-expression:
1121 new object-creation-what
1123 let (parser, new_token
) = assert_token
parser New
in
1124 let (parser, new_what
) =
1125 let (parser1, token) = next_token
parser in
1126 begin match Token.kind token with
1127 | Class
-> parse_anonymous_class
token parser1
1128 | _
-> parse_constructor_call
parser
1130 let result = make_object_creation_expression new_token new_what
in
1133 and parse_anonymous_class class_token
parser =
1134 let class_token = make_token
class_token in
1135 let (parser, left, args
, right) =
1136 if peek_token_kind
parser = LeftParen
1137 then parse_expression_list_opt
parser
1139 let missing1 = make_missing
parser in
1140 let missing2 = make_missing
parser in
1141 let missing3 = make_missing
parser in
1142 (parser, missing1, missing2, missing3)
1145 , ( classish_extends
1146 , classish_extends_list
1147 , classish_implements
1148 , classish_implements_list
1151 = with_decl_parser parser
1153 let (decl_parser, classish_extends
, classish_extends_list
) =
1154 DeclParser.parse_classish_extends_opt
decl_parser in
1155 let (decl_parser, classish_implements
, classish_implements_list
) =
1156 DeclParser.parse_classish_implements_opt
decl_parser in
1157 let (decl_parser, body
) = DeclParser.parse_classish_body
decl_parser in
1159 , ( classish_extends
1160 , classish_extends_list
1161 , classish_implements
1162 , classish_implements_list
1167 let result = make_anonymous_class
class_token left args
right
1168 classish_extends classish_extends_list classish_implements
1169 classish_implements_list body
in
1172 and parse_constructor_call
parser =
1175 class-type-designator ( argument-expression-list-opt )
1177 (* PHP allows the entire expression list to be omitted. *)
1178 (* TODO: SPEC ERROR: PHP allows the entire expression list to be omitted,
1179 * but Hack disallows this behavior. (See SyntaxError.error2038.) However,
1180 * the Hack spec still states that the argument expression list is optional.
1181 * Update the spec to say that the argument expression list is required. *)
1182 let (parser, designator
) = parse_designator
parser in
1183 let (parser, left, args
, right) =
1184 if peek_token_kind
parser = LeftParen
then
1185 parse_expression_list_opt
parser
1187 let missing1 = make_missing
parser in
1188 let missing2 = make_missing
parser in
1189 let missing3 = make_missing
parser in
1190 (parser, missing1, missing2, missing3)
1193 make_constructor_call designator
left args
right in
1196 and parse_function_call
parser receiver
=
1198 function-call-expression:
1199 postfix-expression ( argument-expression-list-opt )
1201 let (parser, left, args
, right) = parse_expression_list_opt
parser in
1202 let result = make_function_call_expression receiver
left args
right in
1203 parse_remaining_expression
parser result
1205 and parse_variable_or_lambda
parser =
1206 let (parser1, variable
) = assert_token
parser Variable
in
1207 if peek_token_kind
parser1 = EqualEqualGreaterThan
then
1208 parse_lambda_expression
parser
1210 (parser1, make_variable_expression variable
)
1212 and parse_yield_expression
parser =
1214 yield array-element-initializer
1215 TODO: Hack allows "yield break".
1216 TODO: Should this be its own production, or can it be a yield expression?
1217 TODO: Is this an expression or a statement?
1218 TODO: Add it to the specification.
1220 let parser, yield_kw
= assert_token
parser Yield
in
1221 match peek_token_kind
parser with
1223 let parser, from_kw
= assert_token
parser From
in
1224 let parser, operand
= parse_expression parser in
1225 parser, make_yield_from_expression yield_kw from_kw operand
1227 let parser, break_kw
= assert_token
parser Break
in
1228 parser, make_yield_expression yield_kw break_kw
1230 let missing = make_missing
parser in
1231 let yield_expr = make_yield_expression yield_kw
missing in
1234 let parser, operand
= parse_array_element_init
parser in
1235 parser, make_yield_expression yield_kw operand
1237 and parse_cast_or_parenthesized_or_lambda_expression
parser =
1238 (* We need to disambiguate between casts, lambdas and ordinary
1239 parenthesized expressions. *)
1240 match possible_cast_expression
parser with
1241 | Some
(parser, left, cast_type
, right) ->
1242 let (parser, operand
) = parse_expression_with_operator_precedence
1243 parser Operator.CastOperator
in
1244 let result = make_cast_expression
left cast_type
right operand
in
1247 match possible_lambda_expression
parser with
1248 | Some
(parser, signature
) ->
1249 parse_lambda_expression_after_signature
parser signature
1251 parse_parenthesized_expression
parser
1254 and token_implies_cast
kind =
1255 (* See comments below. *)
1257 (* Keywords that imply cast *)
1262 | TokenKind.Attribute
1357 (* Names that imply cast *)
1361 (* Symbols that imply cast *)
1372 (* Literals that imply cast *)
1376 | DoubleQuotedStringLiteral
1377 | DoubleQuotedStringLiteralHead
1379 | DoubleQuotedStringLiteralTail
1380 | ExecutionStringLiteral
1381 | ExecutionStringLiteralHead
1382 | ExecutionStringLiteralTail
1384 | HeredocStringLiteral
1385 | HeredocStringLiteralHead
1386 | HeredocStringLiteralTail
1387 | HexadecimalLiteral
1388 | NowdocStringLiteral
1391 | SingleQuotedStringLiteral
-> true
1392 (* Keywords that imply parenthesized expression *)
1399 (* Symbols that imply parenthesized expression *)
1401 | AmpersandAmpersand
1418 | EqualEqualGreaterThan
1421 | LessThanGreaterThan
1422 | ExclamationEqualEqual
1425 | GreaterThanGreaterThan
1426 | GreaterThanGreaterThanEqual
1427 | LessThanLessThanEqual
1431 | QuestionMinusGreaterThan
1441 | LessThanEqualGreaterThan
1453 | StarStarEqual
-> false
1457 | QuestionGreaterThan
1459 | TokenKind.EndOfFile
-> false
1460 (* TODO: Sort out rules for interactions between casts and XHP. *)
1467 | XHPComment
-> false
1469 and possible_cast_expression
parser =
1472 ( cast-type ) unary-expression
1474 array, bool, double, float, int, object, string, unset or a name
1476 TODO: This implies that a cast "(name)" can only be a simple name, but
1477 I would expect that (\Foo\Bar), (:foo), (array<int>), and the like
1478 should also be legal casts. If we implement that then we will need
1479 a sophisticated heuristic to determine whether this is a cast or a
1480 parenthesized expression.
1482 The cast expression introduces an ambiguity: (x)-y could be a
1483 subtraction or a cast on top of a unary minus. We resolve this
1484 ambiguity as follows:
1486 * If the thing in parens is one of the keywords mentioned above, then
1488 * If the token which follows (x) is "as" or "instanceof" then
1489 it's a parenthesized expression.
1490 * PHP-ism extension: if the token is "and", "or" or "xor", then it's a
1491 parenthesized expression.
1492 * Otherwise, if the token which follows (x) is $$, @, ~, !, (, +, -,
1493 any name, qualified name, variable name, literal, or keyword then
1495 * Otherwise, it's a parenthesized expression. *)
1497 let (parser, left_paren
) = assert_token
parser LeftParen
in
1498 let (parser, type_token
) = next_token
parser in
1499 let type_token_kind = Token.kind type_token
in
1500 let (parser, right_paren
) = next_token
parser in
1501 let is_easy_cast_type_or_at_least_name =
1502 match type_token_kind with
1503 | Array
| Bool
| Double
| Float
| Int
| Object
| String
| Unset
-> Some
true
1504 | Name
-> Some
false
1506 let is_cast = Token.kind right_paren
= RightParen
&&
1507 Option.value_map ~
default:false is_easy_cast_type_or_at_least_name
1508 ~
f:(fun b
-> b
|| token_implies_cast
(peek_token_kind
parser)) in
1510 Some
(parser, left_paren
, make_token type_token
, make_token right_paren
)
1514 and possible_lambda_expression
parser =
1515 (* We have a left paren in hand and we already know we're not in a cast.
1516 We need to know whether this is a parenthesized expression or the
1517 signature of a lambda.
1519 There are a number of difficulties. For example, we cannot simply
1520 check to see if a colon follows the expression:
1522 $a = $b ? ($x) : ($y) ($x) is parenthesized expression
1523 $a = $b ? ($x) : int ==> 1 : ($y) ($x) is lambda signature
1527 What we'll do here is simply attempt to parse a lambda formal parameter
1528 list. If we manage to do so *without error*, and the thing which follows
1529 is ==>, then this is definitely a lambda. If those conditions are not
1530 met then we assume we have a parenthesized expression in hand.
1532 TODO: There could be situations where we have good evidence that a
1533 lambda is intended but these conditions are not met. Consider
1534 a more sophisticated recovery strategy. For example, if we have
1535 (x)==> then odds are pretty good that a lambda was intended and the
1536 error should say that ($x)==> was expected.
1538 let signature_result = parse_if_no_error
parser parse_lambda_signature
in
1539 match signature_result with
1540 | Some
(parser, _
) when (peek_token_kind
parser) = EqualEqualGreaterThan
->
1544 and parse_lambda_expression
parser =
1547 async-opt lambda-function-signature ==> lambda-body
1549 let (parser, async
) = optional_token
parser Async
in
1550 let (parser, coroutine
) = optional_token
parser Coroutine
in
1551 let (parser, signature
) = parse_lambda_signature
parser in
1552 let (parser, arrow
) = require_lambda_arrow
parser in
1553 let (parser, body
) = parse_lambda_body
parser in
1554 let result = make_lambda_expression async coroutine signature arrow body
in
1557 and parse_lambda_expression_after_signature
parser signature
=
1558 (* We had a signature with no async or coroutine, and we disambiguated it
1560 let async = make_missing
parser in
1561 let coroutine = make_missing
parser in
1562 let (parser, arrow
) = require_lambda_arrow
parser in
1563 let (parser, body
) = parse_lambda_body
parser in
1564 let result = make_lambda_expression
async coroutine signature arrow body
in
1567 and parse_lambda_signature
parser =
1569 lambda-function-signature:
1571 ( anonymous-function-parameter-declaration-list-opt ) /
1572 anonymous-function-return-opt
1574 let (parser1, token) = next_token
parser in
1575 if Token.kind token = Variable
then
1576 (parser1, make_token
token)
1578 let (parser, left, params
, right) = parse_parameter_list_opt parser in
1579 let (parser, colon
, return_type
) = parse_optional_return
parser in
1580 let result = make_lambda_signature
left params
right colon return_type
in
1583 and parse_lambda_body
parser =
1589 if peek_token_kind
parser = LeftBrace
then
1590 parse_compound_statement parser
1592 with_reset_precedence
parser parse_expression
1594 and parse_parenthesized_expression
parser =
1595 let (parser, left_paren
) = assert_token
parser LeftParen
in
1596 let (parser, expression
) = with_reset_precedence
parser parse_expression in
1597 let (parser, right_paren
) = require_right_paren
parser in
1599 make_parenthesized_expression left_paren expression right_paren
in
1602 and parse_postfix_unary
parser term
=
1603 let (parser, token) = next_token
parser in
1604 let term = make_postfix_unary_expression
term (make_token
token) in
1605 parse_remaining_expression
parser term
1607 and parse_prefix_unary_expression
parser =
1608 (* TODO: Operand to ++ and -- must be an lvalue. *)
1609 let (parser, token) = next_token
parser in
1610 let kind = Token.kind token in
1611 let operator = Operator.prefix_unary_from_token
kind in
1612 let token = make_token
token in
1613 let (parser, operand
) = parse_expression_with_operator_precedence
1615 make_and_track_prefix_unary_expression parser token kind operand
1617 and parse_simple_variable
parser =
1618 match peek_token_kind
parser with
1620 let (parser1, variable
) = next_token
parser in
1621 (parser1, make_token variable
)
1622 | Dollar
-> parse_dollar_expression
parser
1623 | _
-> require_variable
parser
1625 and parse_dollar_expression
parser =
1626 let (parser, dollar
) = assert_token
parser Dollar
in
1627 let (parser, operand
) =
1628 match peek_token_kind
parser with
1630 parse_braced_expression
parser
1631 | Variable
when Env.php5_compat_mode
(env parser) ->
1632 parse_variable_in_php5_compat_mode
parser
1634 parse_expression_with_operator_precedence
parser
1635 (Operator.prefix_unary_from_token Dollar
) in
1636 make_and_track_prefix_unary_expression parser dollar Dollar operand
1638 and parse_instanceof_expression
parser left =
1640 instanceof-expression:
1641 instanceof-subject instanceof instanceof-type-designator
1646 instanceof-type-designator:
1650 TODO: The spec is plainly wrong here. This is a bit of a mess and there
1651 are a number of issues.
1653 The issues arise from the fact that the thing on the right can be either
1654 a type, or an expression that evaluates to a string that names the type.
1656 The grammar in the spec, above, says that the only things that can be
1657 here are a qualified name -- in which case it names the type directly --
1658 or a variable of classname type, which names the type. But this is
1659 not the grammar that is accepted by Hack / HHVM. The accepted grammar
1660 treats "instanceof" as a binary operator which takes expressions on
1661 each side, and is of lower precedence than ->. Thus
1663 $x instanceof $y -> z
1665 must be parsed as ($x instanceof ($y -> z)), and not, as the grammar
1666 implies, (($x instanceof $y) -> z).
1668 But wait, it gets worse.
1670 The less-than operator is of lower precedence than instanceof, so
1671 "$x instanceof foo < 10" should be parsed as (($x instanceof foo) < 10).
1672 But it seems plausible that we might want to parse
1673 "$x instanceof foo<int>" someday, in which case now we have an ambiguity.
1674 How do we know when we see the < whether we are attempting to parse a type?
1676 Moreover: we need to be able to parse XHP class names on the right hand
1677 side of the operator. That is, we need to be able to say
1681 However, we cannot simply say that the grammar is
1683 instanceof-type-designator:
1687 Why not? Because that then gives the wrong parse for:
1689 class :foo { static $bar = "abc" }
1692 $x instanceof :foo :: $bar
1694 We need to parse that as $x instanceof (:foo :: $bar).
1696 The solution to all this is as follows.
1698 First, an XHP class name must be a legal expression. I had thought that
1699 it might be possible to say that an XHP class name is a legal type, or
1700 legal in an expression context when immediately followed by ::, but
1701 that's not the case. We need to be able to parse both
1703 $x instanceof :foo :: $bar
1709 so the most expedient way to do that is to parse any expression on the
1710 right, and to make XHP class names into legal expressions.
1712 So, with all this in mind, the grammar we will actually parse here is:
1714 instanceof-type-designator:
1717 This has the unfortunate property that the common case, say,
1721 creates a parse node for C as a name token, not as a name token wrapped
1722 up as a simple type.
1724 Should we ever need to parse both arbitrary expressions and arbitrary
1725 types here, we'll have some tricky problems to solve.
1728 let (parser, op) = assert_token
parser Instanceof
in
1729 let precedence = Operator.precedence Operator.InstanceofOperator
in
1730 let (parser, right_term
) = parse_term
parser in
1731 let (parser, right) = parse_remaining_binary_expression_helper
1732 parser right_term
precedence in
1733 let result = make_instanceof_expression
left op right in
1734 parse_remaining_expression
parser result
1736 and parse_is_expression
parser left =
1739 is-subject is type-specifier
1744 let (parser, op) = assert_token
parser Is
in
1745 let (parser, right) =
1746 with_type_parser parser TypeParser.parse_type_specifier
1748 let result = make_is_expression
left op right in
1749 parse_remaining_expression
parser result
1751 and parse_remaining_binary_expression
1752 parser left_term
assignment_prefix_kind =
1753 (* We have a left term. If we get here then we know that
1754 * we have a binary operator to its right, and that furthermore,
1755 * the binary operator is of equal or higher precedence than the
1756 * whatever is going on in the left term.
1758 * Here's how this works. Suppose we have something like
1762 * where A, B and C are terms, and x and y are operators.
1763 * We must determine whether this parses as
1771 * We have the former if either x is higher precedence than y,
1772 * or x and y are the same precedence and x is left associative.
1773 * Otherwise, if x is lower precedence than y, or x is right
1774 * associative, then we have the latter.
1776 * How are we going to figure this out?
1778 * We have the term A in hand; the precedence is low.
1779 * We see that x follows A.
1780 * We obtain the precedence of x. It is higher than the precedence of A,
1781 * so we obtain B, and then we call a helper method that
1782 * collects together everything to the right of B that is
1783 * of higher precedence than x. (Or equal, and right-associative.)
1785 * So, if x is of lower precedence than y (or equal and right-assoc)
1786 * then the helper will construct (B y C) as the right term, and then
1787 * we'll make A x (B y C), and we're done. Otherwise, the helper
1788 * will simply return B, we'll construct (A x B) and recurse with that
1791 let is_rhs_of_assignment = assignment_prefix_kind <> Prefix_none
in
1792 assert (not
(next_is_lower_precedence
parser) || is_rhs_of_assignment);
1794 let (parser1, token) = next_token
parser in
1795 let operator = Operator.trailing_from_token
(Token.kind token) in
1797 let precedence = Operator.precedence operator in
1798 let (parser2
, right_term
) =
1799 if is_rhs_of_assignment then
1800 (* reset the current precedence to make sure that expression on
1801 the right hand side of the assignment is fully consumed *)
1802 with_reset_precedence
parser1 parse_term
1804 parse_term
parser1 in
1805 let (parser2
, right_term
) = parse_remaining_binary_expression_helper
1806 parser2 right_term
precedence in
1807 let term = make_binary_expression
1808 left_term
(make_token
token) right_term
in
1809 parse_remaining_expression parser2
term
1811 (*if we are on the right hand side of the assignment - peek if next
1812 token is '&'. If it is - then parse next term. If overall next term is
1813 '&'PHP variable then the overall expression should be parsed as
1814 ... (left_term = & right_term) ...
1816 if assignment_prefix_kind = Prefix_byref_assignment
&&
1817 Token.kind (peek_token
parser1) = Ampersand
then
1818 let (parser2
, right_term
) =
1819 parse_term
@@ with_precedence
1821 Operator.precedence_for_assignment_in_expressions
in
1822 if is_byref_assignment_source parser2 right_term
then
1823 let left_term = make_binary_expression
1824 left_term (make_token
token) right_term
1826 let (parser2
, left_term) = parse_remaining_binary_expression_helper
1827 parser2
left_term parser.precedence
1829 parse_remaining_expression parser2
left_term
1835 and parse_remaining_binary_expression_helper
1836 parser right_term left_precedence
=
1837 (* This gathers up terms to the right of an operator that are
1838 operands of operators of higher precedence than the
1839 operator to the left. For instance, if we have
1840 A + B * C / D + E and we just parsed A +, then we want to
1841 gather up B * C / D into the right side of the +.
1842 In this case "right term" would be B and "left precedence"
1843 would be the precedence of +.
1844 See comments above for more details. *)
1845 let kind = Token.kind (peek_token
parser) in
1846 if Operator.is_trailing_operator_token
kind then
1847 let right_operator = Operator.trailing_from_token
kind in
1848 let right_precedence = Operator.precedence right_operator in
1849 let associativity = Operator.associativity right_operator in
1850 let is_parsable_as_assignment =
1851 (* check if this is the case ... $a = ...
1853 'left_precedence' - precedence of the operation on the left of $a
1855 'kind' - operator that follows right_term
1857 in case if right_term is valid left hand side for the assignment
1858 and token is assignment operator and left_precedence is less than
1859 bumped priority fort the assignment we reset precedence before parsing
1860 right hand side of the assignment to make sure it is consumed.
1862 check_if_parsable_as_assignment
1866 left_precedence
<> Prefix_none
1868 if right_precedence > left_precedence
||
1869 (associativity = Operator.RightAssociative
&&
1870 right_precedence = left_precedence
) ||
1871 is_parsable_as_assignment then
1872 let (parser2
, right_term
) =
1874 if is_parsable_as_assignment then
1875 (* if expression can be parsed as an assignment, keep track of
1876 the precedence on the left of the assignment (it is ok since
1877 we'll internally boost the precedence when parsing rhs of the
1879 This is necessary for cases like:
1880 ... + $a = &$b * $c + ...
1883 it should be parsed as
1884 (... + ($a = &$b) * $c) + ...
1885 when we are at position (#)
1886 - we will first consume byref assignment as a e1
1887 - check that precedence of '*' is greater than precedence of
1888 the '+' (left_precedence) and consume e1 * $c as $e2
1889 - check that precedence of '+' is less or equal than precedence
1890 of the '+' (left_precedence) and stop so the final result
1891 before we get to the point ($) will be
1898 let parser1 = with_precedence
parser precedence in
1899 parse_remaining_expression
parser1 right_term
1901 let parser3 = with_precedence parser2
parser.precedence in
1902 parse_remaining_binary_expression_helper
1903 parser3 right_term left_precedence
1905 (parser, right_term
)
1907 (parser, right_term
)
1909 and parse_conditional_expression
parser test question
=
1910 (* POSSIBLE SPEC PROBLEM
1911 We allow any expression, including assignment expressions, to be in
1912 the consequence and alternative of a conditional expression, even
1913 though assignment is lower precedence than ?:. This is legal:
1914 $a ? $b = $c : $d = $e
1915 Interestingly, this is illegal in C and Java, which require parens,
1918 let kind = peek_token_kind
parser in
1919 (* e1 ?: e2 -- where there is no consequence -- is legal.
1920 However this introduces an ambiguity:
1927 We assume the latter.
1928 TODO: Review this decision.
1929 TODO: Add this to the XHP draft specification.
1931 let missing_consequence =
1932 kind = Colon
&& not
(is_next_xhp_class_name
parser) in
1933 let (parser, consequence
) =
1934 if missing_consequence then
1935 let missing = make_missing
parser in
1938 with_reset_precedence
parser parse_expression
1940 let (parser, colon
) = require_colon
parser in
1941 let (parser, term) = parse_term
parser in
1942 let precedence = Operator.precedence Operator.ConditionalQuestionOperator
in
1943 let (parser, alternative
) = parse_remaining_binary_expression_helper
1944 parser term precedence in
1945 let result = make_conditional_expression
1946 test question consequence colon alternative
in
1949 and parse_name_or_collection_literal_expression
parser name
=
1950 match peek_token_kind
parser with
1952 let name = make_simple_type_specifier
name in
1953 parse_collection_literal_expression
parser name
1955 let (parser1, (type_arguments
, no_arg_is_missing
)) =
1956 parse_generic_type_arguments_opt parser
1958 if no_arg_is_missing
1959 && is_type_arguments type_arguments
1960 && parser.errors = parser1.errors
1961 && peek_token_kind
parser1 = LeftBrace
1963 let name = make_generic_type_specifier
name type_arguments
in
1964 parse_collection_literal_expression
parser1 name
1970 and parse_collection_literal_expression
parser name =
1974 key-collection-class-type { cl-initializer-list-with-keys-opt }
1975 non-key-collection-class-type { cl-initializer-list-without-keys-opt }
1976 pair-type { cl-element-value , cl-element-value }
1978 The types are grammatically qualified names; however the specification
1979 states that they must be as follows:
1980 * keyed collection type can be Map or ImmMap
1981 * non-keyed collection type can be Vector, ImmVector, Set or ImmSet
1982 * pair type can be Pair
1984 We will not attempt to determine if the names give the name of an
1985 appropriate type here. That's for the type checker.
1987 The argumment lists are:
1989 * for keyed, an optional comma-separated list of
1990 expression => expression pairs
1991 * for non-keyed, an optional comma-separated list of expressions
1992 * for pairs, a comma-separated list of exactly two expressions
1994 In all three cases, the lists may be comma-terminated.
1995 TODO: This fact is not represented in the specification; it should be.
1996 This work item is tracked by spec issue #109.
1999 let (parser, left_brace
, initialization_list
, right_brace) =
2000 parse_braced_comma_list_opt_allow_trailing
parser parse_init_expression
in
2001 (* Validating the name is a collection type happens in a later phase *)
2002 let syntax = make_collection_literal_expression
2003 name left_brace initialization_list
right_brace in
2006 and parse_init_expression
parser =
2008 We expect either a list of expr, expr, expr, ... or
2009 expr => expr, expr => expr, expr => expr, ...
2010 Rather than require at parse time that the list be all one or the other,
2011 we allow both, and give an error in the type checker.
2013 let parser, expr1
= parse_expression_with_reset_precedence
parser in
2014 let parser, arrow
= optional_token
parser TokenKind.EqualGreaterThan
in
2015 if is_missing arrow
then
2018 let parser, expr2
= parse_expression_with_reset_precedence
parser in
2019 let syntax = make_element_initializer expr1 arrow expr2
in
2022 and parse_keyed_element_initializer
parser =
2023 let parser, expr1
= parse_expression_with_reset_precedence
parser in
2024 let parser, arrow
= require_arrow
parser in
2025 let parser, expr2
= parse_expression_with_reset_precedence
parser in
2026 let syntax = make_element_initializer expr1 arrow expr2
in
2029 and parse_list_expression
parser =
2032 list ( expression-list-opt )
2035 expression-list , expression-opt
2037 See https://github.com/hhvm/hack-langspec/issues/82
2039 list-intrinsic must be used as the left-hand operand in a
2040 simple-assignment-expression of which the right-hand operand
2041 must be an expression that designates a vector-like array or
2042 an instance of the class types Vector, ImmVector, or Pair
2045 TODO: Produce an error later if the expressions in the list destructuring
2048 let (parser, keyword
) = assert_token
parser List
in
2049 let (parser, left, items
, right) =
2050 parse_parenthesized_comma_list_opt_items_opt
2051 parser parse_expression_with_reset_precedence
in
2052 let result = make_list_expression keyword
left items
right in
2056 * array_intrinsic := array ( array-initializer-opt )
2058 and parse_array_intrinsic_expression
parser =
2059 let (parser, array_keyword
) = assert_token
parser Array
in
2060 let (parser, left_paren
, members
, right_paren
) =
2061 parse_parenthesized_comma_list_opt_allow_trailing
2062 parser parse_array_element_init
in
2063 let syntax = make_array_intrinsic_expression array_keyword left_paren
2064 members right_paren
in
2067 and parse_bracketed_collection_intrinsic_expression
2070 parse_element_function
2071 make_intrinsinc_function
=
2072 let (parser1, keyword
) = assert_token
parser keyword_token
in
2073 let (parser1, left_bracket
) = optional_token
parser1 LeftBracket
in
2074 if is_missing left_bracket
then
2075 (* Fall back to dict being an ordinary name. Perhaps we're calling a
2076 function whose name is indicated by the keyword_token, for example. *)
2077 parse_as_name_or_error
parser
2079 let (parser, members
) =
2080 parse_comma_list_opt_allow_trailing
2083 SyntaxError.error1015
2084 parse_element_function
in
2085 let (parser, right_bracket
) = require_right_bracket
parser in
2087 make_intrinsinc_function keyword left_bracket members right_bracket
in
2091 and parse_darray_intrinsic_expression
parser =
2092 (* TODO: Create the grammar and add it to the spec. *)
2093 parse_bracketed_collection_intrinsic_expression
2096 parse_keyed_element_initializer
2097 make_darray_intrinsic_expression
2099 and parse_dictionary_intrinsic_expression
parser =
2100 (* TODO: Create the grammar and add it to the spec. *)
2101 (* TODO: Can the list have a trailing comma? *)
2102 parse_bracketed_collection_intrinsic_expression
2105 parse_keyed_element_initializer
2106 make_dictionary_intrinsic_expression
2108 and parse_keyset_intrinsic_expression
parser =
2109 parse_bracketed_collection_intrinsic_expression
2112 parse_expression_with_reset_precedence
2113 make_keyset_intrinsic_expression
2115 and parse_varray_intrinsic_expression
parser =
2116 (* TODO: Create the grammar and add it to the spec. *)
2117 parse_bracketed_collection_intrinsic_expression
2120 parse_expression_with_reset_precedence
2121 make_varray_intrinsic_expression
2123 and parse_vector_intrinsic_expression
parser =
2124 (* TODO: Create the grammar and add it to the spec. *)
2125 (* TODO: Can the list have a trailing comma? *)
2126 parse_bracketed_collection_intrinsic_expression
2129 parse_expression_with_reset_precedence
2130 make_vector_intrinsic_expression
2132 (* array_creation_expression :=
2133 [ array-initializer-opt ]
2134 array-initializer :=
2135 array-initializer-list ,-opt
2136 array-initializer-list :=
2137 array-element-initializer
2138 array-element-initializer , array-initializer-list
2140 and parse_array_creation_expression
parser =
2141 let (parser, left_bracket
, members
, right_bracket
) =
2142 parse_bracketted_comma_list_opt_allow_trailing
2143 parser parse_array_element_init
in
2144 let syntax = make_array_creation_expression left_bracket
2145 members right_bracket
in
2148 (* array-element-initializer :=
2150 * expression => expression
2152 and parse_array_element_init
parser =
2154 with_reset_precedence
parser parse_expression in
2155 let parser1, token = next_token
parser in
2156 match Token.kind token with
2157 | EqualGreaterThan
->
2158 let parser, expr2
= with_reset_precedence
parser1 parse_expression in
2159 let arrow = make_token
token in
2160 let result = make_element_initializer expr1
arrow expr2
in
2162 | _
-> (parser, expr1
)
2164 and parse_field_initializer
parser =
2167 single-quoted-string-literal => expression
2168 double_quoted_string_literal => expression
2169 qualified-name => expression
2170 scope-resolution-expression => expression
2173 (* Specification is wrong, and fixing it is being tracked by
2174 * https://github.com/hhvm/hack-langspec/issues/108
2177 (* ERROR RECOVERY: We allow any expression on the left-hand side,
2178 * even though only some expressions are legal;
2179 * we will give an error in a later pass
2181 let (parser, name) = with_reset_precedence
parser parse_expression in
2182 let (parser, arrow) = require_arrow
parser in
2183 let (parser, value) = with_reset_precedence
parser parse_expression in
2184 let result = make_field_initializer
name arrow value in
2187 and parse_shape_expression
parser =
2190 shape ( field-initializer-list-opt )
2192 field-initializer-list:
2193 field-initializers ,-op
2197 field-initializers , field-initializer
2199 let (parser, shape
) = assert_token
parser Shape
in
2200 let (parser, left_paren
, fields
, right_paren
) =
2201 parse_parenthesized_comma_list_opt_allow_trailing
2202 parser parse_field_initializer
in
2203 let result = make_shape_expression shape left_paren fields right_paren
in
2206 and parse_tuple_expression
parser =
2209 tuple ( expression-list-one-or-more )
2211 expression-list-one-or-more:
2213 expression-list-one-or-more , expression
2215 TODO: Can the list be comma-terminated? If so, update the spec.
2216 TODO: We need to produce an error in a later pass if the list is empty.
2218 let (parser, keyword
) = assert_token
parser Tuple
in
2219 let (parser, left_paren
, items
, right_paren
) =
2220 parse_parenthesized_comma_list_opt_allow_trailing
2221 parser parse_expression_with_reset_precedence
in
2222 let result = make_tuple_expression keyword left_paren items right_paren
in
2225 and parse_use_variable
parser =
2226 (* TODO: Is it better that this returns the variable as a *token*, or
2227 as an *expression* that consists of the token? We do the former. *)
2228 let (parser, ampersand
) = optional_token
parser Ampersand
in
2229 let (parser, variable
) = require_variable
parser in
2230 if is_missing ampersand
then
2233 make_and_track_prefix_unary_expression parser ampersand Ampersand variable
2235 and parse_anon_or_lambda_or_awaitable
parser =
2236 (* TODO: The original Hack parser accepts "async" as an identifier, and
2237 so we do too. We might consider making it reserved. *)
2238 (* Skip any async or coroutine declarations that may be present. When we
2239 feed the original parser into the syntax parsers. they will take care of
2240 them as appropriate. *)
2241 let (parser1, _
) = optional_token
parser Static
in
2242 let (parser1, _
) = optional_token
parser1 Async
in
2243 let (parser1, _
) = optional_token
parser1 Coroutine
in
2244 match peek_token_kind
parser1 with
2245 | Function
-> parse_anon
parser
2246 | LeftBrace
-> parse_async_block
parser
2248 | LeftParen
-> parse_lambda_expression
parser
2249 | _
-> parse_as_name_or_error
parser
2251 and parse_async_block
parser =
2254 * awaitable-creation-expression :
2255 * async-opt coroutine-opt compound-statement
2256 * TODO awaitable-creation-expression must not be used as the
2257 * anonymous-function-body in a lambda-expression
2259 let parser, async = optional_token
parser Async
in
2260 let parser, coroutine = optional_token
parser Coroutine
in
2261 let parser, stmt
= parse_compound_statement parser in
2262 parser, make_awaitable_creation_expression
async coroutine stmt
2264 and parse_anon_use_opt
parser =
2266 anonymous-function-use-clause:
2267 use ( use-variable-name-list ,-opt )
2269 use-variable-name-list:
2271 use-variable-name-list , variable-name
2273 TODO: Strict mode requires that it be a list of variables; in
2274 non-strict mode we allow variables to be decorated with a leading
2275 & to indicate they are captured by reference. We need to give an
2276 error in a later pass for this.
2278 let (parser, use_token
) = optional_token
parser Use
in
2279 if is_missing use_token
then
2280 let missing = make_missing
parser in
2283 let (parser, left, vars
, right) =
2284 parse_parenthesized_comma_list_opt_allow_trailing
2285 parser parse_use_variable
in
2286 let result = make_anonymous_function_use_clause use_token
2291 and parse_optional_return
parser =
2292 (* Parse an optional "colon-folowed-by-return-type" *)
2293 let (parser, colon
) = optional_token
parser Colon
in
2294 let (parser, return_type
) =
2295 if is_missing colon
then
2296 let missing = make_missing
parser in
2299 with_type_parser parser TypeParser.parse_return_type
2301 (parser, colon
, return_type
)
2303 and parse_anon
parser =
2305 anonymous-function-creation-expression:
2306 static-opt async-opt coroutine-opt function
2307 ( anonymous-function-parameter-list-opt )
2308 anonymous-function-return-opt
2309 anonymous-function-use-clauseopt
2312 (* An anonymous function's formal parameter list is the same as a named
2313 function's formal parameter list except that types are optional.
2314 The "..." syntax and trailing commas are supported. We'll simply
2315 parse an optional parameter list; it already takes care of making the
2316 type annotations optional. *)
2317 let (parser, static
) = optional_token
parser Static
in
2318 let (parser, async) = optional_token
parser Async
in
2319 let (parser, coroutine) = optional_token
parser Coroutine
in
2320 let (parser, fn
) = assert_token
parser Function
in
2321 let (parser, left_paren
, params
, right_paren
) =
2322 parse_parameter_list_opt parser in
2323 let (parser, colon
, return_type
, use_clause
, is_php7
) =
2324 let (parser, use_clause
) = parse_anon_use_opt
parser in
2325 if is_missing use_clause
then begin
2326 let (parser, colon
, return_type
) = parse_optional_return
parser in
2327 let (parser, use_clause
) = parse_anon_use_opt
parser in
2328 (parser, colon
, return_type
, use_clause
, false)
2331 (* might be PHP7 style lambda where return type follows use clause *)
2332 let (parser, colon
, return_type
) = parse_optional_return
parser in
2333 (parser, colon
, return_type
, use_clause
, not
(is_missing colon
))
2335 let (parser, body
) = parse_compound_statement parser in
2339 make_php7_anonymous_function
2352 make_anonymous_function
2366 and parse_braced_expression
parser =
2367 let (parser, left_brace
) = assert_token
parser LeftBrace
in
2368 let (parser, expression
) = parse_expression_with_reset_precedence
parser in
2369 let (parser, right_brace) = require_right_brace
parser in
2370 let node = make_braced_expression left_brace expression
right_brace in
2373 and require_right_brace_xhp
parser =
2374 let (parser1, token) = next_xhp_body_token
parser in
2375 if (Token.kind token) = TokenKind.RightBrace
then
2376 (parser1, make_token
token)
2378 (* ERROR RECOVERY: Create a missing token for the expected token,
2379 and continue on from the current token. Don't skip it. *)
2380 let missing = make_missing
parser in
2381 let parser = with_error
parser SyntaxError.error1006
in
2384 and parse_xhp_body_braced_expression
parser =
2385 (* The difference between a regular braced expression and an
2386 XHP body braced expression is:
2387 <foo bar={$x}/*this_is_a_comment*/>{$y}/*this_is_body_text!*/</foo>
2389 let (parser, left_brace
) = assert_token
parser LeftBrace
in
2390 let (parser, expression
) = parse_expression_with_reset_precedence
parser in
2391 let (parser, right_brace) = require_right_brace_xhp
parser in
2392 let node = make_braced_expression left_brace expression
right_brace in
2395 and parse_xhp_attribute
parser =
2396 let (parser'
, token, _
) = next_xhp_element_token
parser in
2397 match (Token.kind token) with
2398 | LeftBrace
-> parse_xhp_spread_attribute
parser
2399 | XHPElementName
-> parse_xhp_simple_attribute
parser'
(make_token
token)
2400 | _
-> (parser, None
)
2402 and parse_xhp_spread_attribute
parser =
2403 let (parser, left_brace
, _
) = next_xhp_element_token
parser in
2404 let (parser, ellipsis
) = assert_token
parser DotDotDot
in
2405 let (parser, expression
) = parse_expression_with_reset_precedence
parser in
2406 let (parser, right_brace) = require_right_brace
parser in
2407 let node = make_xhp_spread_attribute
(make_token left_brace
) ellipsis expression
right_brace in
2410 and parse_xhp_simple_attribute
parser name =
2411 (* Parse the attribute name and then defensively check for well-formed
2412 * attribute assignment *)
2413 let (parser'
, token, _
) = next_xhp_element_token
parser in
2414 if (Token.kind token) != Equal
then
2415 let value = make_missing
parser in
2416 let node = make_xhp_simple_attribute
name (make_missing
parser'
) value in
2417 let parser = with_error
parser SyntaxError.error1016
in
2418 (* ERROR RECOVERY: The = is missing; assume that the name belongs
2419 to the attribute, but that the remainder is missing, and start
2420 looking for the next attribute. *)
2423 let equal = make_token
token in
2424 let (parser''
, token, text
) = next_xhp_element_token
parser'
in
2425 match (Token.kind token) with
2426 | XHPStringLiteral
->
2427 let node = make_xhp_simple_attribute
name equal (make_token
token) in
2428 (parser''
, Some
node)
2430 let (parser, expr) = parse_braced_expression
parser'
in
2431 let node = make_xhp_simple_attribute
name equal expr in
2434 (* ERROR RECOVERY: The expression is missing; assume that the "name ="
2435 belongs to the attribute and start looking for the next attribute. *)
2436 let node = make_xhp_simple_attribute
name equal (make_missing
parser''
) in
2437 let parser = with_error
parser'
SyntaxError.error1017
in
2440 and parse_xhp_body_element
parser =
2441 let (parser1, token) = next_xhp_body_token
parser in
2442 match Token.kind token with
2444 | XHPBody
-> (parser1, Some
(make_token
token))
2446 let (parser, expr) = parse_xhp_body_braced_expression
parser in
2449 (* If we find a free-floating right-brace in the middle of an XHP body
2450 that's just fine. It's part of the text. However, it is also likely
2451 to be a mis-edit, so we'll keep it as a right-brace token so that
2452 tooling can flag it as suspicious. *)
2453 (parser1, Some
(make_token
token))
2455 let (parser, expr) =
2456 parse_possible_xhp_expression ~consume_trailing_trivia
:false parser in
2458 | _
-> (parser, None
)
2460 and parse_xhp_close ~consume_trailing_trivia
parser _
=
2461 let (parser1, less_than_slash
, _
) = next_xhp_element_token
parser in
2462 if (Token.kind less_than_slash
) = LessThanSlash
then
2463 let (parser2
, name, name_text
) = next_xhp_element_token
parser1 in
2464 if (Token.kind name) = XHPElementName
then
2465 (* TODO: Check that the given and name_text are the same. *)
2466 let (parser3, greater_than
, _
) =
2467 next_xhp_element_token ~no_trailing
:(not consume_trailing_trivia
) parser2
in
2468 if (Token.kind greater_than
) = GreaterThan
then
2469 (parser3, make_xhp_close
(make_token less_than_slash
)
2470 (make_token
name) (make_token greater_than
))
2472 (* ERROR RECOVERY: *)
2473 let parser = with_error parser2
SyntaxError.error1039
in
2474 let less_than_slash_token = make_token less_than_slash
in
2475 let name_token = make_token
name in
2476 let missing = make_missing
parser in
2477 (parser, make_xhp_close
less_than_slash_token name_token missing)
2479 (* ERROR RECOVERY: *)
2480 let parser = with_error
parser1 SyntaxError.error1039
in
2481 let less_than_slash_token = make_token less_than_slash
in
2482 let missing1 = make_missing
parser in
2483 let missing2 = make_missing
parser in
2484 (parser, make_xhp_close
less_than_slash_token missing1 missing2)
2486 (* ERROR RECOVERY: We probably got a < without a following / or name.
2487 TODO: For now we'll just bail out. We could use a more
2488 sophisticated strategy here. *)
2489 let parser = with_error
parser1 SyntaxError.error1026
in
2490 let less_than_slash_token = make_token less_than_slash
in
2491 let missing1 = make_missing
parser in
2492 let missing2 = make_missing
parser in
2493 (parser, make_xhp_close
less_than_slash_token missing1 missing2)
2495 and parse_xhp_expression ~consume_trailing_trivia
parser left_angle
name name_text
=
2496 let (parser, attrs
) = parse_list_until_none
parser parse_xhp_attribute
in
2497 let (parser1, token, _
) = next_xhp_element_token ~no_trailing
:true parser in
2498 match (Token.kind token) with
2499 | SlashGreaterThan
->
2500 let xhp_open = make_xhp_open left_angle
name attrs
(make_token
token) in
2501 let missing1 = make_missing
parser in
2502 let missing2 = make_missing
parser in
2503 let xhp = make_xhp_expression
xhp_open missing1 missing2 in
2506 let xhp_open = make_xhp_open left_angle
name attrs
(make_token
token) in
2507 let (parser, xhp_body
) =
2508 parse_list_until_none
parser1 parse_xhp_body_element
in
2509 let (parser, xhp_close
) = parse_xhp_close ~consume_trailing_trivia
parser name_text
in
2510 let xhp = make_xhp_expression
xhp_open xhp_body xhp_close
in
2513 (* ERROR RECOVERY: Assume the unexpected token belongs to whatever
2515 let missing = make_missing
parser in
2516 let xhp_open = make_xhp_open left_angle
name attrs
missing in
2517 let missing1 = make_missing
parser in
2518 let missing2 = make_missing
parser in
2519 let xhp = make_xhp_expression
xhp_open missing1 missing2 in
2520 let parser = with_error
parser SyntaxError.error1013
in
2523 and parse_possible_xhp_expression ~consume_trailing_trivia
parser =
2524 (* We got a < token where an expression was expected. *)
2525 let (parser, less_than
) = assert_token
parser LessThan
in
2526 let (parser1, name, text
) = next_xhp_element_token
parser in
2527 if (Token.kind name) = XHPElementName
then
2528 parse_xhp_expression
2529 ~consume_trailing_trivia
parser1 less_than
(make_token
name) text
2532 Hard to say what to do here. We are expecting an expression;
2533 we could simply produce an error for the < and call that the
2534 expression. Or we could assume the the left side of an inequality is
2535 missing, give a missing node for the left side, and parse the
2536 remainder as the right side. We'll go for the former for now. *)
2537 (with_error
parser SyntaxError.error1015
, less_than
)
2539 and parse_anon_or_awaitable_or_scope_resolution_or_name
parser =
2540 (* static is a legal identifier, if next token is scope resolution operatpr
2541 - parse expresson as scope resolution operator, otherwise try to interpret
2542 it as anonymous function (will fallback to name in case of failure) *)
2543 if peek_token_kind ~lookahead
:1 parser = ColonColon
then
2544 parse_scope_resolution_or_name
parser
2546 parse_anon_or_lambda_or_awaitable
parser
2548 and parse_scope_resolution_or_name
parser =
2549 (* parent, self and static are legal identifiers. If the next
2550 thing that follows is a scope resolution operator, parse them as
2551 ordinary tokens, and then we'll pick them up as the operand to the
2552 scope resolution operator when we call parse_remaining_expression.
2553 Otherwise, parse them as ordinary names. *)
2554 let (parser1, qualifier
) = next_token
parser in
2555 if peek_token_kind
parser1 = ColonColon
then
2556 (parser1, (make_token qualifier
))
2558 parse_as_name_or_error
parser
2560 and parse_scope_resolution_expression
parser qualifier
=
2562 scope-resolution-expression:
2563 scope-resolution-qualifier :: name
2564 scope-resolution-qualifier :: class
2566 scope-resolution-qualifier:
2573 (* TODO: The left hand side can in fact be any expression in this parser;
2574 we need to add a later error pass to detect that the left hand side is
2575 a valid qualifier. *)
2576 (* TODO: The right hand side, if a name or a variable, is treated as a
2577 name or variable *token* and not a name or variable *expression*. Is
2578 that the desired tree topology? Give this more thought; it might impact
2579 rename refactoring semantics. *)
2580 let (parser, op) = require_coloncolon
parser in
2581 let (parser, name) =
2582 let parser1, token = next_token
parser in
2583 match Token.kind token with
2584 | Class
-> parser1, make_token
token
2585 | Dollar
-> parse_dollar_expression
parser
2586 | LeftBrace
-> parse_braced_expression
parser
2587 | Variable
when Env.php5_compat_mode
(env parser) ->
2588 let parser1, e
= parse_variable_in_php5_compat_mode
parser in
2589 (* for :: only do PHP5 transform for call expressions
2590 in other cases fall back to the regular parsing logic *)
2591 if peek_token_kind
parser1 = LeftParen
&&
2592 (* make sure the left parenthesis means a call
2593 for the expression we are currently parsing, and
2594 are not for example for a constructor call whose
2595 name would be the result of this expression. *)
2596 not
@@ operator_has_lower_precedence LeftParen
parser
2598 else require_name_or_variable_or_error
parser SyntaxError.error1048
2600 require_name_or_variable_or_error
parser SyntaxError.error1048
2602 let result = make_scope_resolution_expression qualifier
op name in
2605 end (* WithSmartConstructors *)
2606 end (* WithSyntax *)