// Port of sqlglot/parser.py: the expression precedence chain.

///|
pub fn Parser::parse_expression(self : Parser) -> Expr? raise SqlglotError {
  match self.fns.hooks.parse_expression {
    Some(f) => f(self)
    None => self.parse_alias(self.parse_assignment())
  }
}

///|
pub fn Parser::parse_assignment(self : Parser) -> Expr? raise SqlglotError {
  match self.fns.hooks.parse_assignment {
    Some(f) => f(self)
    None => self.parse_assignment_base()
  }
}

///|
pub fn Parser::parse_assignment_base(self : Parser) -> Expr? raise SqlglotError {
  let mut this = self.parse_disjunction()
  if this is None && self.cfg.assignment.contains(self.next.token_type) {
    let name = match self.advance_any(ignore_reserved=true) {
      Some(_) => self.prev.text
      None => "False"
    }
    this = Some(column_of(name))
  }
  while self.match_keys(self.cfg.assignment) {
    match this {
      Some(t) if t.kind.is_a(Column) && t.parts().length() == 1 =>
        this = t.this()
      _ => ()
    }
    let comments = self.prev_comments
    let kind = self.cfg.assignment[self.prev.token_type]
    let expression = self.parse_assignment()
    this = Some(
      self.expression(
        mk(kind, [("this", this), ("expression", expression)]),
        comments~,
      ),
    )
  }
  this
}

///|
/// Parses a left-associative binary operator level.
pub fn Parser::parse_binary_level(
  self : Parser,
  table : Map[TokenType, Kind],
  next : () -> Expr? raise SqlglotError,
) -> Expr? raise SqlglotError {
  let mut this = next()
  while self.match_keys(table) {
    let comments = self.prev_comments
    let kind = table[self.prev.token_type]
    let expression = next()
    this = Some(
      self.expression(
        mk(kind, [("this", this), ("expression", expression)]),
        comments~,
      ),
    )
  }
  this
}

///|
pub fn Parser::parse_disjunction(self : Parser) -> Expr? raise SqlglotError {
  self.parse_binary_level(self.cfg.disjunction, () => self.parse_conjunction())
}

///|
pub fn Parser::parse_conjunction(self : Parser) -> Expr? raise SqlglotError {
  self.parse_binary_level(self.cfg.conjunction, () => self.parse_equality())
}

///|
pub fn Parser::parse_equality(self : Parser) -> Expr? raise SqlglotError {
  match self.fns.hooks.parse_equality {
    Some(f) => f(self)
    None =>
      self.parse_binary_level(self.cfg.equality, () => self.parse_comparison())
  }
}

///|
pub fn Parser::parse_comparison(self : Parser) -> Expr? raise SqlglotError {
  self.parse_binary_level(self.cfg.comparison, () => self.parse_range())
}

///|
pub fn Parser::parse_range(
  self : Parser,
  this? : Expr?,
) -> Expr? raise SqlglotError {
  let this : Expr? = match this {
    Some(t) => t
    None => None
  }
  match self.fns.hooks.parse_range {
    Some(f) => f(self, this)
    None => self.parse_range_base(this)
  }
}

///|
pub fn Parser::parse_range_base(
  self : Parser,
  this : Expr?,
) -> Expr? raise SqlglotError {
  let mut this = expr_or(this, () => self.parse_bitwise())
  while true {
    let negate = self.match_(NOT)
    if self.match_keys(self.fns.range_parsers) {
      let parser = self.fns.range_parsers[self.prev.token_type]
      match parser(self, this) {
        None => return this
        Some(e) => this = Some(e)
      }
    } else if self.match_(ISNULL) || (negate && self.match_(NULL)) {
      this = Some(
        self.expression(mk(Is, [("this", this), ("expression", null_())])),
      )
    } else if self.match_(NOTNULL) {
      if self.dialect.cfg.normalize_not_null {
        this = Some(
          self.expression(mk(Is, [("this", this), ("expression", null_())])),
        )
        this = Some(self.expression(mk1(Not, this)))
      } else {
        this = Some(
          self.expression(
            mk(Is, [("this", this), ("expression", null_()), ("negate", true)]),
          ),
        )
      }
    } else {
      if negate {
        self.retreat(self.index - 1)
      }
      break
    }
    if negate {
      this = self.negate_range(this)
      if self.curr.ok() &&
        (
          self.curr.token_type == NOT ||
          self.fns.range_parsers.contains(self.curr.token_type)
        ) {
        this = Some(self.expression(mk1(Paren, this)))
      }
    }
  }
  this
}

///|
pub fn Parser::negate_range(
  self : Parser,
  this : Expr?,
) -> Expr? raise SqlglotError {
  match self.fns.hooks.negate_range {
    Some(f) => f(self, this)
    None => self.negate_range_base(this)
  }
}

///|
pub fn Parser::negate_range_base(
  self : Parser,
  this : Expr?,
) -> Expr? raise SqlglotError {
  let t = match this {
    Some(t) => t
    None => return this
  }
  let expression = if t.kind == Escape {
    match t.this() {
      Some(x) => x
      None => t
    }
  } else {
    t
  }
  if expression.kind.is_any([Like, ILike]) {
    expression.set("negate", true)
    return this
  }
  Some(self.expression(mk1(Not, this)))
}

///|
pub fn Parser::parse_is(
  self : Parser,
  this : Expr?,
) -> Expr? raise SqlglotError {
  let index = self.index - 1
  let negate = self.match_(NOT)
  if self.match_text_seq(["DISTINCT", "FROM"]) {
    let klass = if negate { NullSafeEQ } else { NullSafeNEQ }
    return Some(
      self.expression(
        mk(klass, [("this", this), ("expression", self.parse_bitwise())]),
      ),
    )
  }
  let mut expression : Expr? = None
  if self.match_(JSON) {
    let kind : Value = if self.match_text_set(self.cfg.is_json_predicate_kind) {
      Str(self.prev_upper())
    } else {
      Bool(false)
    }
    let with_ : Bool? = if self.match_text("WITH") {
      Some(true)
    } else if self.match_text("WITHOUT") {
      Some(false)
    } else {
      None
    }
    let unique = self.match_(UNIQUE)
    self.match_text("KEYS") |> ignore
    expression = Some(
      self.expression(
        mk(JSON, [("this", kind), ("with_", with_), ("unique", unique)]),
      ),
    )
  } else {
    expression = expr_or(self.parse_null(), () => self.parse_bitwise())
    if expression is None {
      self.retreat(index)
      return None
    }
  }
  let mut this = this
  match expression {
    Some(e) if negate && e.kind == Null && !self.dialect.cfg.normalize_not_null =>
      this = Some(
        self.expression(
          mk(Is, [("this", this), ("expression", e), ("negate", true)]),
        ),
      )
    _ => {
      this = Some(
        self.expression(mk(Is, [("this", this), ("expression", expression)])),
      )
      if negate {
        this = Some(self.expression(mk1(Not, this)))
      }
    }
  }
  self.parse_column_ops(this)
}

///|
pub fn Parser::parse_in(
  self : Parser,
  this : Expr?,
  alias? : Bool = false,
) -> Expr? raise SqlglotError {
  let mut this = this
  match self.parse_unnest(with_alias=false) {
    Some(unnest) =>
      this = Some(self.expression(mk(In, [("this", this), ("unnest", unnest)])))
    None =>
      if self.match_any([L_PAREN, L_BRACKET]) {
        let matched_l_paren = self.prev.token_type == L_PAREN
        let expressions = self.parse_csv(() => {
          self.parse_select_or_expression(alias~)
        })
        if expressions.length() == 1 && expressions[0].kind.is_a(Query) {
          let query = expressions[0]
          let q = self.parse_query_modifiers(Some(query)).unwrap()
          this = Some(
            self.expression(
              mk(In, [("this", this), ("query", q.subquery(copy=false))]),
            ),
          )
        } else {
          this = Some(
            self.expression(
              mk(In, [("this", this), ("expressions", expressions)]),
            ),
          )
        }
        if matched_l_paren {
          self.match_r_paren(expression?=this)
        } else if !self.match_(R_BRACKET, expression?=this) {
          self.raise_error("Expecting ]")
        }
      } else {
        this = Some(
          self.expression(
            mk(In, [("this", this), ("field", self.parse_column())]),
          ),
        )
      }
  }
  this
}

///|
pub fn Parser::parse_between(
  self : Parser,
  this : Expr?,
) -> Expr? raise SqlglotError {
  let symmetric : Bool? = if self.match_text("SYMMETRIC") {
    Some(true)
  } else if self.match_text("ASYMMETRIC") {
    Some(false)
  } else {
    None
  }
  let low = self.parse_bitwise()
  self.match_(AND) |> ignore
  let high = self.parse_bitwise()
  Some(
    self.expression(
      mk(Between, [
        ("this", this),
        ("low", low),
        ("high", high),
        ("symmetric", symmetric),
      ]),
    ),
  )
}

///|
pub fn Parser::parse_escape(
  self : Parser,
  this : Expr?,
) -> Expr? raise SqlglotError {
  if !self.match_(ESCAPE) {
    return this
  }
  let expression = expr_or(self.parse_string(), () => self.parse_null())
  Some(
    self.expression(mk(Escape, [("this", this), ("expression", expression)])),
  )
}

///|
/// `INTERVAL_DAY_TIME_RE.match(text)`:
/// `\s*-?\s*\d+(?:\.\d+)?\s+(?:-?(?:\d+:)?\d+:\d+(?:\.\d+)?|-?(?:\d+:){1,2}|:)\s*`
pub fn interval_day_time_match(text : String) -> Bool {
  let s = text.to_array()
  let n = s.length()
  let mut i = 0
  fn skip_ws() {
    while i < n && is_space(s[i]) {
      i += 1
    }
  }

  fn digits() -> Bool {
    let st = i
    while i < n && is_decimal(s[i]) {
      i += 1
    }
    i > st
  }

  skip_ws()
  if i < n && s[i] == '-' {
    i += 1
  }
  skip_ws()
  if !digits() {
    return false
  }
  if i < n && s[i] == '.' {
    let save = i
    i += 1
    if !digits() {
      i = save
    }
  }
  let ws_start = i
  skip_ws()
  if i == ws_start {
    return false
  }
  // alternatives (prefix match only, `re.match`)
  let start = i
  // alt 1: -?(?:\d+:)?\d+:\d+(?:\.\d+)?
  fn alt1() -> Bool {
    i = start
    if i < n && s[i] == '-' {
      i += 1
    }
    let save = i
    // try (\d+:) prefix then \d+:\d+
    fn tail() -> Bool {
      if !digits() {
        return false
      }
      if !(i < n && s[i] == ':') {
        return false
      }
      i += 1
      if !digits() {
        return false
      }
      if i < n && s[i] == '.' {
        let sv = i
        i += 1
        if !digits() {
          i = sv
        }
      }
      true
    }

    if digits() && i < n && s[i] == ':' {
      i += 1
      let save2 = i
      if tail() {
        return true
      }
      i = save2
    }
    i = save
    tail()
  }

  // alt 2: -?(?:\d+:){1,2}
  fn alt2() -> Bool {
    i = start
    if i < n && s[i] == '-' {
      i += 1
    }
    let mut count = 0
    while count < 2 {
      let save = i
      if digits() && i < n && s[i] == ':' {
        i += 1
        count += 1
      } else {
        i = save
        break
      }
    }
    count >= 1
  }

  alt1() || alt2() || (start < n && s[start] == ':')
}

///|
/// `INTERVAL_STRING_RE.findall(text)` returning (value, unit) pairs:
/// `\s*(-?[0-9]+(?:\.[0-9]+)?)\s*([a-zA-Z]+)\s*`
pub fn interval_string_findall(text : String) -> Array[(String, String)] {
  let s = text.to_array()
  let n = s.length()
  let out = []
  let mut pos = 0
  while pos <= n {
    // try to match at pos
    let mut i = pos
    while i < n && is_space(s[i]) {
      i += 1
    }
    let num_start = i
    if i < n && s[i] == '-' {
      i += 1
    }
    let d0 = i
    while i < n && s[i] >= '0' && s[i] <= '9' {
      i += 1
    }
    let mut ok = i > d0
    if ok && i < n && s[i] == '.' {
      let save = i
      i += 1
      let d1 = i
      while i < n && s[i] >= '0' && s[i] <= '9' {
        i += 1
      }
      if i == d1 {
        i = save
      }
    }
    let num_end = i
    if ok {
      while i < n && is_space(s[i]) {
        i += 1
      }
      let u0 = i
      while i < n && s[i].is_ascii_alphabetic() {
        i += 1
      }
      if i > u0 {
        let unit = String::from_array(s[u0:i])
        while i < n && is_space(s[i]) {
          i += 1
        }
        out.push((String::from_array(s[num_start:num_end]), unit))
        pos = i
        continue
      }
      ok = false
    }
    pos += 1
  }
  out
}

///|
pub fn Parser::parse_interval_span(
  self : Parser,
  this : Expr?,
  parse_function_unit? : Bool = true,
) -> Expr raise SqlglotError {
  let mut this = this
  let mut interval_span_units_omitted : Bool? = None
  match this {
    Some(t) if t.is_string() &&
      self.cfg.supports_omitted_interval_span_unit &&
      interval_day_time_match(t.name()) => {
      let index = self.index
      let first_unit = self.parse_var(any_token=true, upper=true)
      let mut second_unit : Expr? = None
      if first_unit is Some(_) && self.match_text("TO") {
        second_unit = self.parse_var(any_token=true, upper=true)
      }
      interval_span_units_omitted = Some(
        !(first_unit is Some(_) && second_unit is Some(_)),
      )
      self.retreat(index)
    }
    _ => ()
  }
  let unit_index = self.index
  let mut unit : Expr? = None
  if interval_span_units_omitted == Some(true) {
    unit = None
  } else {
    let is_unit = self.curr.ok() &&
      (
        self.curr.token_type == VAR ||
        self.dialect.cfg.valid_interval_units.contains(py_upper(self.curr.text))
      )
    unit = if parse_function_unit && is_unit {
      self.parse_function()
    } else {
      None
    }
    if unit is None && is_unit {
      unit = self.parse_var(any_token=true, upper=true)
    }
  }
  match this {
    Some(t) if t.is_number() =>
      match t.to_py_int() {
        Some(v) => this = Some(literal_string(v.to_string()))
        None =>
          match t.to_py_float() {
            Some(_) => this = Some(literal_string(decimal_str(t)))
            None =>
              self.raise_error(
                "Invalid numeric interval literal: \{py_repr_str(t.name())}",
              )
          }
      }
    Some(t) if t.is_string() => {
      let parts = interval_string_findall(t.name())
      if !parts.is_empty() && unit is Some(_) {
        unit = None
        self.retreat(unit_index)
      }
      if parts.length() == 1 {
        this = Some(literal_string(parts[0].0))
        unit = Some(self.expression(mk1(Var, py_upper(parts[0].1))))
      }
    }
    _ => ()
  }
  if self.cfg.interval_spans && self.match_text("TO") {
    let expression = expr_or(self.parse_function(), () => {
      self.parse_var(any_token=true, upper=true)
    })
    unit = Some(
      self.expression(
        mk(IntervalSpan, [("this", unit), ("expression", expression)]),
      ),
    )
  }
  self.expression(mk(Interval, [("this", this), ("unit", unit)]))
}

///|
/// Python `str(Decimal(text))` for a numeric literal (used for INTERVAL values).
fn decimal_str(t : Expr) -> String {
  let neg = t.kind == Neg
  let lit = if neg {
    match t.this() {
      Some(x) => x
      None => t
    }
  } else {
    t
  }
  let text = lit.text("this")
  let s = py_decimal_str(text)
  if neg {
    "-" + s
  } else {
    s
  }
}

///|
/// Python `str(Decimal(text))`: keeps the literal mostly as written, normalizing
/// exponent formatting and leading `+`/`.`.
pub fn py_decimal_str(text : String) -> String {
  let t = py_strip(text)
  let lower = py_lower(t)
  match lower.find("e") {
    Some(epos) => {
      // Decimal('1e5') -> '1E+5'; Decimal('1.5e-3') -> '0.0015'
      let mant = substr(t, 0, epos)
      let exp_s = substr(t, epos + 1, py_len(t))
      let exp_v = match parse_int_str(exp_s) {
        Some(v) => v.to_int()
        None => 0
      }
      let (sign, digits0) = if mant.has_prefix("-") {
        ("-", substr(mant, 1, py_len(mant)))
      } else if mant.has_prefix("+") {
        ("", substr(mant, 1, py_len(mant)))
      } else {
        ("", mant)
      }
      let (int_part, frac_part) = match digits0.find(".") {
        Some(d) =>
          (substr(digits0, 0, d), substr(digits0, d + 1, py_len(digits0)))
        None => (digits0, "")
      }
      let mut coeff = int_part + frac_part
      let mut exponent = exp_v - py_len(frac_part)
      // strip leading zeros of the coefficient (keep at least one digit)
      while py_len(coeff) > 1 && coeff.has_prefix("0") {
        coeff = substr(coeff, 1, py_len(coeff))
      }
      let ndigits = py_len(coeff)
      let adjusted = exponent + ndigits - 1
      if exponent <= 0 && adjusted >= -6 {
        // fixed point
        if exponent == 0 {
          sign + coeff
        } else {
          let point = ndigits + exponent
          if point > 0 {
            sign + substr(coeff, 0, point) + "." + substr(coeff, point, ndigits)
          } else {
            sign + "0." + "0".repeat(-point) + coeff
          }
        }
      } else {
        // scientific
        let first = substr(coeff, 0, 1)
        let rest = substr(coeff, 1, ndigits)
        let mant_s = if rest.is_empty() { first } else { first + "." + rest }
        let es = if adjusted >= 0 { "+\{adjusted}" } else { "\{adjusted}" }
        exponent = adjusted
        ignore(exponent)
        sign + mant_s + "E" + es
      }
    }
    None => {
      let mut s = t
      let mut sign = ""
      if s.has_prefix("+") {
        s = substr(s, 1, py_len(s))
      } else if s.has_prefix("-") {
        sign = "-"
        s = substr(s, 1, py_len(s))
      }
      if s.has_prefix(".") {
        s = "0" + s
      }
      if s.has_suffix(".") {
        s = substr(s, 0, -1)
      }
      // strip leading zeros of the integer part
      while py_len(s) > 1 && s.has_prefix("0") && substr(s, 1, 2) != "." {
        s = substr(s, 1, py_len(s))
      }
      sign + s
    }
  }
}

///|
pub fn Parser::parse_interval(
  self : Parser,
  require_interval? : Bool = true,
  parse_function_unit? : Bool = true,
) -> Expr? raise SqlglotError {
  let index = self.index
  if !self.match_(INTERVAL) && require_interval {
    return None
  }
  let this = if self.match_(STRING, advance=false) {
    self.parse_primary()
  } else {
    self.parse_term()
  }
  let reject = match this {
    None => true
    Some(t) =>
      t.kind.is_a(Column) &&
      t.table_name().is_empty() &&
      !(match t.this() {
        Some(i) => i.has("quoted")
        None => false
      }) &&
      self.curr.ok() &&
      !self.dialect.cfg.valid_interval_units.contains(py_upper(self.curr.text))
  }
  if reject {
    self.retreat(index)
    return None
  }
  let interval = self.parse_interval_span(this, parse_function_unit~)
  let index = self.index
  self.match_(PLUS) |> ignore
  if self.match_any([STRING, NUMBER], advance=false) {
    let rest = self.parse_interval(require_interval=false, parse_function_unit~)
    return Some(
      self.expression(mk(Add, [("this", interval), ("expression", rest)])),
    )
  }
  self.retreat(index)
  Some(interval)
}

///|
pub fn Parser::parse_bitwise(self : Parser) -> Expr? raise SqlglotError {
  let mut this = self.parse_term()
  while true {
    if self.match_keys(self.cfg.bitwise) {
      let kind = self.cfg.bitwise[self.prev.token_type]
      this = Some(
        self.expression(
          mk(kind, [("this", this), ("expression", self.parse_term())]),
        ),
      )
    } else if self.dialect.cfg.dpipe_is_string_concat && self.match_(DPIPE) {
      this = Some(
        self.expression(
          mk(DPipe, [
            ("this", this),
            ("expression", self.parse_term()),
            ("safe", !self.dialect.cfg.strict_string_concat),
          ]),
        ),
      )
    } else if self.match_(DQMARK) {
      let t = self.parse_term()
      this = Some(
        self.expression(
          mk(Coalesce, [("this", this), ("expressions", [t].filter_map(x => x))]),
        ),
      )
    } else if self.match_pair(LT, LT) {
      this = Some(
        self.expression(
          mk(BitwiseLeftShift, [
            ("this", this),
            ("expression", self.parse_term()),
          ]),
        ),
      )
    } else if self.match_pair(GT, GT) {
      this = Some(
        self.expression(
          mk(BitwiseRightShift, [
            ("this", this),
            ("expression", self.parse_term()),
          ]),
        ),
      )
    } else if !self.fns.json_operators.is_empty() &&
      self.match_keys(self.fns.json_operators) {
      let op = self.fns.json_operators[self.prev.token_type]
      this = op(self, this, self.parse_term())
    } else {
      break
    }
  }
  this
}

///|
pub fn Parser::parse_term(
  self : Parser,
  parse_mod? : Bool = true,
) -> Expr? raise SqlglotError {
  let mut this = self.parse_factor(parse_mod~)
  while self.match_keys(self.cfg.term) {
    let klass = self.cfg.term[self.prev.token_type]
    let comments = self.prev_comments
    let expression = self.parse_factor(parse_mod~)
    let e = self.expression(
      mk(klass, [("this", this), ("expression", expression)]),
      comments~,
    )
    if e.kind == Collate {
      self.normalize_collate(e)
    }
    this = Some(e)
  }
  this
}

///|
pub fn Parser::normalize_collate(self : Parser, collate : Expr) -> Unit {
  ignore(self)
  match collate.expression() {
    Some(expr) if expr.kind.is_a(Column) && expr.parts().length() == 1 =>
      match expr.this() {
        Some(ident) if ident.kind == Identifier =>
          collate.set(
            "expression",
            if ident.has("quoted") {
              ident
            } else {
              var_(ident.name())
            },
          )
        _ => ()
      }
    _ => ()
  }
}

///|
pub fn Parser::parse_factor(
  self : Parser,
  parse_mod? : Bool = true,
) -> Expr? raise SqlglotError {
  let mut this = self.parse_at_time_zone(self.parse_factor_operand())
  while self.match_keys(self.cfg.factor, advance=false) {
    if !parse_mod && self.curr.token_type == MOD {
      break
    }
    self.advance()
    let klass = self.cfg.factor[self.prev.token_type]
    let comments = self.prev_comments
    let expression = self.parse_factor_operand()
    if expression is None &&
      klass == IntDiv &&
      self.prev.text.iter().all(is_alpha) &&
      !self.prev.text.is_empty() {
      self.retreat(self.index - 1)
      return this
    }
    let e = self.expression(
      mk(klass, [("this", this), ("expression", expression)]),
      comments~,
    )
    if e.kind == Div {
      e.set("typed", self.dialect.cfg.typed_division)
      e.set("safe", self.dialect.cfg.safe_division)
    }
    this = Some(e)
  }
  this
}

///|
pub fn Parser::parse_factor_operand(self : Parser) -> Expr? raise SqlglotError {
  match self.fns.hooks.parse_factor_operand {
    Some(f) => f(self)
    None =>
      if !self.cfg.exponent.is_empty() {
        self.parse_exponent()
      } else {
        self.parse_unary()
      }
  }
}

///|
pub fn Parser::parse_exponent(self : Parser) -> Expr? raise SqlglotError {
  self.parse_binary_level(self.cfg.exponent, () => self.parse_unary())
}

///|
pub fn Parser::parse_unary(self : Parser) -> Expr? raise SqlglotError {
  if self.match_keys(self.fns.unary_parsers) {
    let parser = self.fns.unary_parsers[self.prev.token_type]
    return parser(self)
  }
  self.parse_type()
}

///|
/// `TIME_ZONE_RE.search(text)`: `:.*?[a-zA-Z\+\-]` (`.` doesn't match newlines)
fn time_zone_re_search(text : String) -> Bool {
  let chars = text.to_array()
  for i, c in chars {
    if c == ':' {
      for j in (i + 1).. Expr? raise SqlglotError {
  match self.fns.hooks.parse_type {
    Some(f) => f(self, parse_interval, fallback_to_identifier)
    None => self.parse_type_base(parse_interval~, fallback_to_identifier~)
  }
}

///|
pub fn Parser::parse_type_base(
  self : Parser,
  parse_interval? : Bool = true,
  fallback_to_identifier? : Bool = false,
) -> Expr? raise SqlglotError {
  if !fallback_to_identifier {
    match self.parse_atom() {
      Some(atom) => return Some(atom)
      None => ()
    }
  }
  if parse_interval {
    match self.parse_interval() {
      Some(interval) => return self.parse_column_ops(Some(interval))
      None => ()
    }
  }
  let index = self.index
  let data_type = self.parse_types(check_func=true, allow_identifiers=false)
  match data_type {
    Some(dt) if dt.kind.is_a(Cast) => return self.parse_column_ops(Some(dt))
    Some(dt) => {
      let index2 = self.index
      let this = self.parse_primary()
      match this {
        Some(lit) if lit.kind == Literal => {
          let literal = lit.name()
          let this = self.parse_column_ops(Some(lit))
          match dt.args.get("this") {
            Some(DT(dtype)) =>
              match self.fns.type_literal_parsers.get(dtype) {
                Some(parser) => return Some(parser(self, this.unwrap(), dt))
                None => ()
              }
            _ => ()
          }
          let mut data_type = dt
          if self.cfg.zone_aware_timestamp_constructor &&
            time_zone_re_search(literal) {
            if data_type.is_type([DType::TIMESTAMP]) {
              data_type = mk1(DataType, DType::TIMESTAMPTZ)
            } else if data_type.is_type([DType::TIME]) {
              data_type = mk1(DataType, DType::TIMETZ)
            }
          }
          return Some(
            self.expression(mk(Cast, [("this", this), ("to", data_type)])),
          )
        }
        _ => ()
      }
      if !dt.expressions().is_empty() && index2 - index > 1 {
        self.retreat(index2)
        return self.parse_column_ops(Some(dt))
      }
      self.retreat(index)
    }
    None => ()
  }
  if fallback_to_identifier {
    return self.parse_id_var()
  }
  self.parse_column()
}

///|
pub fn Parser::parse_type_size(self : Parser) -> Expr? raise SqlglotError {
  let mut this = match self.parse_type() {
    Some(t) => t
    None => return None
  }
  if this.kind.is_a(Column) && this.table_name().is_empty() {
    this = var_(py_upper(this.name()))
  }
  Some(
    self.expression(
      mk(DataTypeParam, [
        ("this", this),
        ("expression", self.parse_var(any_token=true)),
      ]),
    ),
  )
}

///|
pub fn Parser::parse_user_defined_type(
  self : Parser,
  identifier : Expr,
) -> Expr? raise SqlglotError {
  match self.fns.hooks.parse_user_defined_type {
    Some(f) => f(self, identifier)
    None => self.parse_user_defined_type_base(identifier)
  }
}

///|
pub fn Parser::parse_user_defined_type_base(
  self : Parser,
  identifier : Expr,
) -> Expr? raise SqlglotError {
  let mut type_name = identifier.name()
  while self.match_(DOT) {
    let part = match self.advance_any() {
      Some(_) => self.prev.text
      None => "None"
    }
    type_name = "\{type_name}.\{part}"
  }
  Some(datatype_from_str(type_name, dialect=self.dialect, udt=true))
}