<commit_before>(**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *)

module Ast = Flow_ast

open Token
open Parser_env
open Flow_ast
module Error = Parse_error
open Parser_common

module type EXPRESSION = sig
  val assignment: env -> (Loc.t, Loc.t) Expression.t
  val assignment_cover: env -> pattern_cover
  val conditional: env -> (Loc.t, Loc.t) Expression.t
  val property_name_include_private: env -> Loc.t * (Loc.t, Loc.t) Identifier.t * bool
  val is_assignable_lhs: (Loc.t, Loc.t) Expression.t -> bool
  val left_hand_side: env -> (Loc.t, Loc.t) Expression.t
  val number: env -> number_type -> string -> float
  val sequence: env -> (Loc.t, Loc.t) Expression.t list -> (Loc.t, Loc.t) Expression.t
end

module Expression
  (Parse: PARSER)
  (Type: Type_parser.TYPE)
  (Declaration: Declaration_parser.DECLARATION)
  (Pattern_cover: Pattern_cover.COVER)
: EXPRESSION = struct
  type op_precedence = Left_assoc of int | Right_assoc of int
  let is_tighter a b =
    let a_prec = match a with Left_assoc x -> x | Right_assoc x -> x - 1 in
    let b_prec = match b with Left_assoc x -> x | Right_assoc x -> x in
    a_prec >= b_prec

  let is_assignable_lhs = Expression.(function
    | _, MetaProperty { MetaProperty.meta = (_, { Identifier.name= "new"; comments= _ }); property = (_, { Identifier.name= "target"; comments= _ }) }
      -> false (* #sec-static-semantics-static-semantics-isvalidsimpleassignmenttarget *)

    | _, Array _
    | _, Identifier _
    | _, Member _
    | _, MetaProperty _
    | _, Object _
      -> true

    | _, ArrowFunction _
    | _, Assignment _
    | _, Binary _
    | _, Call _
    | _, Class _
    | _, Comprehension _
    | _, Conditional _
    | _, Function _
    | _, Generator _
    | _, Import _
    | _, JSXElement _
    | _, JSXFragment _
    | _, Literal _
    | _, Logical _
    | _, New _
    | _, OptionalCall _
    | _, OptionalMember _
    | _, Sequence _
    | _, Super
    | _, TaggedTemplate _
    | _, TemplateLiteral _
    | _, This
    | _, TypeCast _
    | _, Unary _
    | _, Update _
    | _, Yield _
      -> false
  )

  let as_expression = Pattern_cover.as_expression
  let as_pattern = Pattern_cover.as_pattern

  (* AssignmentExpression :
   *   ConditionalExpression
   *   LeftHandSideExpression = AssignmentExpression
   *   LeftHandSideExpression AssignmentOperator AssignmentExpression
   *   ArrowFunctionFunction
   *
   *   Originally we were parsing this without backtracking, but
   *   ArrowFunctionExpression got too tricky. Oh well.
   *)
  let rec assignment_cover =
    let assignment_but_not_arrow_function_cover env =
      let expr_or_pattern = conditional_cover env in
      match assignment_op env with
      | Some operator ->
        let left = as_pattern env expr_or_pattern in
        let right = assignment env in
        let loc = Loc.btwn (fst left) (fst right) in

        Cover_expr (loc, Expression.(Assignment { Assignment.
          operator;
          left;
          right;
        }))
      | _ -> expr_or_pattern

    in let error_callback _ = function
      (* Don't rollback on these errors. *)
      | Error.StrictReservedWord -> ()
      (* Everything else causes a rollback *)
      | _ -> raise Try.Rollback

    (* So we may or may not be parsing the first part of an arrow function
     * (the part before the =>). We might end up parsing that whole thing or
     * we might end up parsing only part of it and thinking we're done. We
     * need to look at the next token to figure out if we really parsed an
     * assignment expression or if this is just the beginning of an arrow
     * function *)
    in let try_assignment_but_not_arrow_function env =
      let env = env |> with_error_callback error_callback in
      let ret = assignment_but_not_arrow_function_cover env in
      match Peek.token env with
      | T_ARROW -> (* x => 123 *)
        raise Try.Rollback
      | T_COLON when last_token env = Some T_RPAREN-> (* (x): number => 123 *)
        raise Try.Rollback
      (* async x => 123 -- and we've already parsed async as an identifier
       * expression *)
      | _ when Peek.is_identifier env -> begin match ret with
        | Cover_expr (_, Expression.Identifier (_, { Identifier.name= "async"; comments= _ }))
            when not (Peek.is_line_terminator env) ->
          raise Try.Rollback
        | _ -> ret
        end
      | _ -> ret
    in fun env ->
      match Peek.token env, Peek.is_identifier env with
      | T_YIELD, _ when (allow_yield env) -> Cover_expr (yield env)
      | T_LPAREN, _
      | T_LESS_THAN, _
      | _, true ->

        (* Ok, we don't know if this is going to be an arrow function or a
         * regular assignment expression. Let's first try to parse it as an
         * assignment expression. If that fails we'll try an arrow function.
         *)
        (match Try.to_parse env try_assignment_but_not_arrow_function with
        | Try.ParsedSuccessfully expr -> expr
        | Try.FailedToParse ->
          (match Try.to_parse env try_arrow_function with
            | Try.ParsedSuccessfully expr -> expr
            | Try.FailedToParse ->

                (* Well shoot. It doesn't parse cleanly as a normal
                 * expression or as an arrow_function. Let's treat it as a
                 * normal assignment expression gone wrong *)
                assignment_but_not_arrow_function_cover env
          )
        )
      | _ -> assignment_but_not_arrow_function_cover env

  and assignment env =
    as_expression env (assignment_cover env)

  and yield env = with_loc (fun env ->
    if in_formal_parameters env then error env Error.YieldInFormalParameters;
    Expect.token env T_YIELD;
    let argument, delegate =
      if Peek.is_implicit_semicolon env then None, false
      else
        let delegate = Expect.maybe env T_MULT in
        let has_argument = match Peek.token env with
          | T_SEMICOLON
          | T_RBRACKET
          | T_RCURLY
          | T_RPAREN
          | T_COLON
          | T_COMMA -> false
          | _ -> true
        in
        let argument =
          if delegate || has_argument
          then Some (assignment env)
          else None in
        argument, delegate
    in
    Expression.(Yield Yield.({
      argument;
      delegate;
    }))
  ) env

  and is_lhs = Expression.(function
    | _, MetaProperty { MetaProperty.meta = (_, { Identifier.name= "new"; comments= _ }); property = (_, { Identifier.name= "target"; comments= _ }) }
      -> false (* #sec-static-semantics-static-semantics-isvalidsimpleassignmenttarget *)

    | _, Identifier _
    | _, Member _
    | _, MetaProperty _
      -> true

    | _, Array _
    | _, ArrowFunction _
    | _, Assignment _
    | _, Binary _
    | _, Call _
    | _, Class _
    | _, Comprehension _
    | _, Conditional _
    | _, Function _
    | _, Generator _
    | _, Import _
    | _, JSXElement _
    | _, JSXFragment _
    | _, Literal _
    | _, Logical _
    | _, New _
    | _, Object _
    | _, OptionalCall _
    | _, OptionalMember _
    | _, Sequence _
    | _, Super
    | _, TaggedTemplate _
    | _, TemplateLiteral _
    | _, This
    | _, TypeCast _
    | _, Unary _
    | _, Update _
    | _, Yield _
      -> false
  )

  and assignment_op env =
    let op = Expression.Assignment.(match Peek.token env with
    | T_RSHIFT3_ASSIGN -> Some (Some RShift3Assign)
    | T_RSHIFT_ASSIGN -> Some (Some RShiftAssign)
    | T_LSHIFT_ASSIGN -> Some (Some LShiftAssign)
    | T_BIT_XOR_ASSIGN -> Some (Some BitXorAssign)
    | T_BIT_OR_ASSIGN -> Some (Some BitOrAssign)
    | T_BIT_AND_ASSIGN -> Some (Some BitAndAssign)
    | T_MOD_ASSIGN -> Some (Some ModAssign)
    | T_DIV_ASSIGN -> Some (Some DivAssign)
    | T_MULT_ASSIGN -> Some (Some MultAssign)
    | T_EXP_ASSIGN -> Some (Some ExpAssign)
    | T_MINUS_ASSIGN -> Some (Some MinusAssign)
    | T_PLUS_ASSIGN -> Some (Some PlusAssign)
    | T_ASSIGN -> Some None
    | _ -> None) in
    if op <> None then Eat.token env;
    op

  and conditional_cover env =
    let start_loc = Peek.loc env in
    let expr = logical_cover env in
    if Peek.token env = T_PLING
    then begin
      Expect.token env T_PLING;
      (* no_in is ignored for the consequent *)
      let env' = env |> with_no_in false in
      let consequent = assignment env' in
      Expect.token env T_COLON;
      let end_loc, alternate = with_loc assignment env in
      let loc = Loc.btwn start_loc end_loc in
      Cover_expr (loc, Expression.(Conditional { Conditional.
        test = as_expression env expr;
        consequent;
        alternate;
      }))
    end else expr

  and conditional env = as_expression env (conditional_cover env)

  and logical_cover =
    let open Expression in
    let make_logical env left right operator loc =
      let left = as_expression env left in
      let right = as_expression env right in
      Cover_expr (loc, Logical {Logical.operator; left; right;})
    in let rec logical_and env left lloc =
      match Peek.token env with
      | T_AND ->
          Expect.token env T_AND;
          let rloc, right = with_loc binary_cover env in
          let loc = Loc.btwn lloc rloc in
          logical_and env (make_logical env left right Logical.And loc) loc
      | _  -> lloc, left
    and logical_or env left lloc =
      let options = parse_options env in
      match Peek.token env with
      | T_OR ->
          Expect.token env T_OR;
          let rloc, right = with_loc binary_cover env in
          let rloc, right = logical_and env right rloc in
          let loc = Loc.btwn lloc rloc in
          logical_or env (make_logical env left right Logical.Or loc) loc
      | T_PLING_PLING ->
          if not options.esproposal_nullish_coalescing
          then error env Parse_error.NullishCoalescingDisabled;

          Expect.token env T_PLING_PLING;<commit_msg>[PR] [parser] Add comments to conditional_cover and logical_cover<commit_after>(**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *)

module Ast = Flow_ast

open Token
open Parser_env
open Flow_ast
module Error = Parse_error
open Parser_common

module type EXPRESSION = sig
  val assignment: env -> (Loc.t, Loc.t) Expression.t
  val assignment_cover: env -> pattern_cover
  val conditional: env -> (Loc.t, Loc.t) Expression.t
  val property_name_include_private: env -> Loc.t * (Loc.t, Loc.t) Identifier.t * bool
  val is_assignable_lhs: (Loc.t, Loc.t) Expression.t -> bool
  val left_hand_side: env -> (Loc.t, Loc.t) Expression.t
  val number: env -> number_type -> string -> float
  val sequence: env -> (Loc.t, Loc.t) Expression.t list -> (Loc.t, Loc.t) Expression.t
end

module Expression
  (Parse: PARSER)
  (Type: Type_parser.TYPE)
  (Declaration: Declaration_parser.DECLARATION)
  (Pattern_cover: Pattern_cover.COVER)
: EXPRESSION = struct
  type op_precedence = Left_assoc of int | Right_assoc of int
  let is_tighter a b =
    let a_prec = match a with Left_assoc x -> x | Right_assoc x -> x - 1 in
    let b_prec = match b with Left_assoc x -> x | Right_assoc x -> x in
    a_prec >= b_prec

  let is_assignable_lhs = Expression.(function
    | _, MetaProperty { MetaProperty.meta = (_, { Identifier.name= "new"; comments= _ }); property = (_, { Identifier.name= "target"; comments= _ }) }
      -> false (* #sec-static-semantics-static-semantics-isvalidsimpleassignmenttarget *)

    | _, Array _
    | _, Identifier _
    | _, Member _
    | _, MetaProperty _
    | _, Object _
      -> true

    | _, ArrowFunction _
    | _, Assignment _
    | _, Binary _
    | _, Call _
    | _, Class _
    | _, Comprehension _
    | _, Conditional _
    | _, Function _
    | _, Generator _
    | _, Import _
    | _, JSXElement _
    | _, JSXFragment _
    | _, Literal _
    | _, Logical _
    | _, New _
    | _, OptionalCall _
    | _, OptionalMember _
    | _, Sequence _
    | _, Super
    | _, TaggedTemplate _
    | _, TemplateLiteral _
    | _, This
    | _, TypeCast _
    | _, Unary _
    | _, Update _
    | _, Yield _
      -> false
  )

  let as_expression = Pattern_cover.as_expression
  let as_pattern = Pattern_cover.as_pattern

  (* AssignmentExpression :
   *   [+Yield] YieldExpression
   *   ConditionalExpression
   *   LeftHandSideExpression = AssignmentExpression
   *   LeftHandSideExpression AssignmentOperator AssignmentExpression
   *   ArrowFunctionFunction
   *
   *   Originally we were parsing this without backtracking, but
   *   ArrowFunctionExpression got too tricky. Oh well.
   *)
  let rec assignment_cover =
    let assignment_but_not_arrow_function_cover env =
      let expr_or_pattern = conditional_cover env in
      match assignment_op env with
      | Some operator ->
        let left = as_pattern env expr_or_pattern in
        let right = assignment env in
        let loc = Loc.btwn (fst left) (fst right) in

        Cover_expr (loc, Expression.(Assignment { Assignment.
          operator;
          left;
          right;
        }))
      | _ -> expr_or_pattern

    in let error_callback _ = function
      (* Don't rollback on these errors. *)
      | Error.StrictReservedWord -> ()
      (* Everything else causes a rollback *)
      | _ -> raise Try.Rollback

    (* So we may or may not be parsing the first part of an arrow function
     * (the part before the =>). We might end up parsing that whole thing or
     * we might end up parsing only part of it and thinking we're done. We
     * need to look at the next token to figure out if we really parsed an
     * assignment expression or if this is just the beginning of an arrow
     * function *)
    in let try_assignment_but_not_arrow_function env =
      let env = env |> with_error_callback error_callback in
      let ret = assignment_but_not_arrow_function_cover env in
      match Peek.token env with
      | T_ARROW -> (* x => 123 *)
        raise Try.Rollback
      | T_COLON when last_token env = Some T_RPAREN-> (* (x): number => 123 *)
        raise Try.Rollback
      (* async x => 123 -- and we've already parsed async as an identifier
       * expression *)
      | _ when Peek.is_identifier env -> begin match ret with
        | Cover_expr (_, Expression.Identifier (_, { Identifier.name= "async"; comments= _ }))
            when not (Peek.is_line_terminator env) ->
          raise Try.Rollback
        | _ -> ret
        end
      | _ -> ret
    in fun env ->
      match Peek.token env, Peek.is_identifier env with
      | T_YIELD, _ when (allow_yield env) -> Cover_expr (yield env)
      | T_LPAREN, _
      | T_LESS_THAN, _
      | _, true ->

        (* Ok, we don't know if this is going to be an arrow function or a
         * regular assignment expression. Let's first try to parse it as an
         * assignment expression. If that fails we'll try an arrow function.
         *)
        (match Try.to_parse env try_assignment_but_not_arrow_function with
        | Try.ParsedSuccessfully expr -> expr
        | Try.FailedToParse ->
          (match Try.to_parse env try_arrow_function with
            | Try.ParsedSuccessfully expr -> expr
            | Try.FailedToParse ->

                (* Well shoot. It doesn't parse cleanly as a normal
                 * expression or as an arrow_function. Let's treat it as a
                 * normal assignment expression gone wrong *)
                assignment_but_not_arrow_function_cover env
          )
        )
      | _ -> assignment_but_not_arrow_function_cover env

  and assignment env =
    as_expression env (assignment_cover env)

  and yield env = with_loc (fun env ->
    if in_formal_parameters env then error env Error.YieldInFormalParameters;
    Expect.token env T_YIELD;
    let argument, delegate =
      if Peek.is_implicit_semicolon env then None, false
      else
        let delegate = Expect.maybe env T_MULT in
        let has_argument = match Peek.token env with
          | T_SEMICOLON
          | T_RBRACKET
          | T_RCURLY
          | T_RPAREN
          | T_COLON
          | T_COMMA -> false
          | _ -> true
        in
        let argument =
          if delegate || has_argument
          then Some (assignment env)
          else None in
        argument, delegate
    in
    Expression.(Yield Yield.({
      argument;
      delegate;
    }))
  ) env

  and is_lhs = Expression.(function
    | _, MetaProperty { MetaProperty.meta = (_, { Identifier.name= "new"; comments= _ }); property = (_, { Identifier.name= "target"; comments= _ }) }
      -> false (* #sec-static-semantics-static-semantics-isvalidsimpleassignmenttarget *)

    | _, Identifier _
    | _, Member _
    | _, MetaProperty _
      -> true

    | _, Array _
    | _, ArrowFunction _
    | _, Assignment _
    | _, Binary _
    | _, Call _
    | _, Class _
    | _, Comprehension _
    | _, Conditional _
    | _, Function _
    | _, Generator _
    | _, Import _
    | _, JSXElement _
    | _, JSXFragment _
    | _, Literal _
    | _, Logical _
    | _, New _
    | _, Object _
    | _, OptionalCall _
    | _, OptionalMember _
    | _, Sequence _
    | _, Super
    | _, TaggedTemplate _
    | _, TemplateLiteral _
    | _, This
    | _, TypeCast _
    | _, Unary _
    | _, Update _
    | _, Yield _
      -> false
  )

  and assignment_op env =
    let op = Expression.Assignment.(match Peek.token env with
    | T_RSHIFT3_ASSIGN -> Some (Some RShift3Assign)
    | T_RSHIFT_ASSIGN -> Some (Some RShiftAssign)
    | T_LSHIFT_ASSIGN -> Some (Some LShiftAssign)
    | T_BIT_XOR_ASSIGN -> Some (Some BitXorAssign)
    | T_BIT_OR_ASSIGN -> Some (Some BitOrAssign)
    | T_BIT_AND_ASSIGN -> Some (Some BitAndAssign)
    | T_MOD_ASSIGN -> Some (Some ModAssign)
    | T_DIV_ASSIGN -> Some (Some DivAssign)
    | T_MULT_ASSIGN -> Some (Some MultAssign)
    | T_EXP_ASSIGN -> Some (Some ExpAssign)
    | T_MINUS_ASSIGN -> Some (Some MinusAssign)
    | T_PLUS_ASSIGN -> Some (Some PlusAssign)
    | T_ASSIGN -> Some None
    | _ -> None) in
    if op <> None then Eat.token env;
    op

  (* ConditionalExpression :
   *   LogicalExpression
   *   LogicalExpression ? AssignmentExpression : AssignmentExpression
   *)
  and conditional_cover env =
    let start_loc = Peek.loc env in
    let expr = logical_cover env in
    if Peek.token env = T_PLING
    then begin
      Expect.token env T_PLING;
      (* no_in is ignored for the consequent *)
      let env' = env |> with_no_in false in
      let consequent = assignment env' in
      Expect.token env T_COLON;
      let end_loc, alternate = with_loc assignment env in
      let loc = Loc.btwn start_loc end_loc in
      Cover_expr (loc, Expression.(Conditional { Conditional.
        test = as_expression env expr;
        consequent;
        alternate;
      }))
    end else expr

  and conditional env = as_expression env (conditional_cover env)

  (*
   * LogicalANDExpression :
   *   BinaryExpression
   *   LogicalANDExpression && BitwiseORExpression
   *
   * LogicalORExpression :
   *   LogicalANDExpression
   *   LogicalORExpression || LogicalANDExpression
   *   LogicalORExpression ?? LogicalANDExpression
   *
   * LogicalExpression :
   *   LogicalORExpression
   *)
  and logical_cover =
    let open Expression in
    let make_logical env left right operator loc =
      let left = as_expression env left in
      let right = as_expression env right in
      Cover_expr (loc, Logical {Logical.operator; left; right;})
    in let rec logical_and env left lloc =
      match Peek.token env with
      | T_AND ->
          Expect.token env T_AND;
          let rloc, right = with_loc binary_cover env in
          let loc = Loc.btwn lloc rloc in
          logical_and env (make_logical env left right Logical.And loc) loc
      | _  -> lloc, left
    and logical_or env left lloc =
      let options = parse_options env in
      match Peek.token env with
      | T_OR ->
          Expect.token env T_OR;
          let rloc, right = with_loc binary_cover env in
          let rloc, right = logical_and env right rloc in
          let loc = Loc.btwn lloc rloc in
          logical_or env (make_logical env left right Logical.Or loc) loc
      | T_PLING_PLING ->
          if not options.esproposal_nullish_coalescing
          then error env Parse_error.NullishCoalescingDisabled;

          Expect.token env T_PLING_PLING;
{'fraction_non_alphanumeric': 0.08026739533522007, 'fraction_numerical': 0.0011710744608178004, 'mean_word_length': 2.3163430420711975, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 139, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3690489', 'n_tokens_mistral': 6300, 'n_tokens_neox': 6131, 'n_words': 1867}