///|
#valtype
priv struct Parenthesized {
  items : PendingEdges
  outer_scope : Int
  parameter_scope : Int
  trailing_comma : Bool
}

///|
/// Parse the common prefix of an expression, call and arrow parameter list once.
/// The provisional scope is retained for arrows and collapsed otherwise.
fn Parser::parenthesized(self : Parser) -> Parenthesized raise ParseError {
  let outer_scope = self.scope
  let parameter_scope = self.program.push_scope(
    outer_scope, scope_arrow_parameters,
  )
  self.scope = parameter_scope
  self.expect(LeftParenthesis)
  let items = self.begin_edges()
  let mut trailing_comma = false
  while self.lexer.token != RightParenthesis {
    let item = if self.eat(Ellipsis) {
      let inner = self.assignment_with_in()
      self.program.node(Spread, inner, 0, 0, 0)
    } else {
      self.assignment_with_in()
    }
    items.push(item)
    guard self.eat(Comma) else { break }
    trailing_comma = self.lexer.token == RightParenthesis
  }
  self.expect(RightParenthesis)
  { items, outer_scope, parameter_scope, trailing_comma, }
}

///|
fn Parser::finish_arrow(
  self : Parser,
  parameters : Parenthesized,
  is_async : Bool,
) -> Int raise ParseError {
  guard !self.lexer.newline_before else {
    raise self.syntax_error("newline before arrow")
  }
  let count = parameters.items.length()
  for index in 0.. Int raise ParseError {
  self.collapse_parenthesized_scope(expression)
  guard !expression.trailing_comma && expression.items.length() > 0 else {
    raise self.syntax_error("invalid parenthesized expression")
  }
  for item in expression.items.view() {
    guard self.program.nodes[item].kind != Spread else {
      raise self.syntax_error("spread requires a parameter or argument list")
    }
  }
  let inner = if expression.items.length() == 1 {
    let inner = expression.items[0]
    expression.items.release()
    inner
  } else {
    let { offset, count, } = self.program.edge_list(expression.items)
    self.program.node(Sequence, offset, count, 0, 0)
  }
  self.program.node(Parenthesized, inner, 0, 0, 0)
}

///|
fn Parser::async_parentheses(
  self : Parser,
  name_start : Int,
  name_end : Int,
) -> Int raise ParseError {
  let expression = self.parenthesized()
  guard self.lexer.token != Arrow else {
    return self.finish_arrow(expression, true)
  }
  self.collapse_parenthesized_scope(expression)
  let reference = self.add_reference(self.scope, name_start, name_end)
  let callee = self.program.node(Identifier, reference, 0, 0, 0)
  let { offset, count, } = self.program.edge_list(expression.items)
  self.program.node(Call, callee, offset, count, 0)
}

///|
/// Reinterpret only binding positions; default-value expressions keep their AST.
fn Parser::cover_pattern(
  self : Parser,
  id : Int,
  declaring : Bool,
) -> Unit raise ParseError {
  let node = self.program.nodes[id]
  let replacement = match node.kind {
    Identifier | PatternIdentifier => self.cover_identifier(node, declaring)
    ArrayLiteral | ObjectLiteral | PatternArray | PatternObject =>
      self.cover_collection(node, declaring)
    Property | PatternProperty => {
      self.cover_pattern(node.b, declaring)
      Node::new(PatternProperty, node.a, node.b, node.c, node.d)
    }
    Spread | PatternRest => self.cover_rest(node, declaring)
    Assignment => {
      guard self.program.operators[node.a] == Operator::Assignment else {
        raise self.syntax_error("invalid default binding")
      }
      self.cover_pattern(node.b, declaring)
      Node::new(PatternDefault, node.b, node.c, 0, 0)
    }
    CoverDefault | PatternDefault => {
      if node.kind == CoverDefault {
        self.program.cover_defaults -= 1
      }
      self.cover_pattern(node.a, declaring)
      Node::new(PatternDefault, node.a, node.b, 0, 0)
    }
    Member | Index if !declaring => node
    _ => raise self.syntax_error("invalid binding pattern")
  }
  self.program.nodes[id] = replacement
}

///|
fn Parser::cover_identifier(
  self : Parser,
  node : Node,
  declaring : Bool,
) -> Node raise ParseError {
  let reference = self.program.references[node.a]
  if declaring {
    let symbol = self.program.add_symbol(
      reference.name_start,
      reference.name_end,
      self.scope,
    )
    self.program.references[node.a] = {
      ..reference,
      scope: self.scope,
      symbol,
    }
  }
  let kind = if declaring { PatternIdentifier } else { Identifier }
  Node::new(kind, node.a, 0, 0, 0)
}

///|
fn Parser::cover_collection(
  self : Parser,
  node : Node,
  declaring : Bool,
) -> Node raise ParseError {
  let is_object = node.kind == ObjectLiteral || node.kind == PatternObject
  for index in 0..= 0 else { continue }
    let element = self.program.nodes[item]
    if element.kind == Spread || element.kind == PatternRest {
      let is_last_without_comma = index == node.b - 1 && node.d == 0
      guard is_last_without_comma else {
        raise self.syntax_error(
          "rest binding must be last without a trailing comma",
        )
      }
      if is_object && declaring {
        self.require_object_rest_identifier(element.a)
      }
    }
    self.cover_pattern(item, declaring)
  }
  let kind = if is_object { PatternObject } else { PatternArray }
  Node::new(kind, node.a, node.b, 0, 0)
}

///|
fn Parser::require_object_rest_identifier(
  self : Parser,
  target : Int,
) -> Unit raise ParseError {
  let kind = self.program.nodes[target].kind
  guard kind == Identifier || kind == PatternIdentifier else {
    raise self.syntax_error("object rest binding requires an identifier")
  }
}

///|
fn Parser::cover_rest(
  self : Parser,
  node : Node,
  declaring : Bool,
) -> Node raise ParseError {
  let target = self.program.nodes[node.a].kind
  let has_default = target == Assignment ||
    target == PatternDefault ||
    target == CoverDefault
  guard !has_default else {
    raise self.syntax_error("rest binding cannot have a default")
  }
  self.cover_pattern(node.a, declaring)
  Node::new(PatternRest, node.a, 0, 0, 0)
}

///|
fn Parser::assignment_pattern(self : Parser, id : Int) -> Unit raise ParseError {
  let kind = self.program.nodes[id].kind
  guard kind == ArrayLiteral || kind == ObjectLiteral else { return }
  self.cover_pattern(id, false)
}

///|
fn Parser::collapse_parenthesized_scope(
  self : Parser,
  expression : Parenthesized,
) -> Unit {
  let scope = self.program.scopes[expression.parameter_scope]
  self.program.scopes[expression.parameter_scope] = {
    ..scope,
    kind: scope_transparent,
  }
  self.scope = expression.outer_scope
}