///|
/// Helper functions for printing basic types
fn print_constant(c : @syntax.Constant, logger : StringBuilder) -> Unit {
  match c {
    Bool(b) => logger.write_string(if b { "true" } else { "false" })
    Char(s) => {
      logger.write_string("'")
      logger.write_string(s)
      logger.write_string("'")
    }
    String(s) => {
      logger.write_string("\"")
      logger.write_string(s)
      logger.write_string("\"")
    }
    UInt64(s) => {
      logger.write_string(s)
      logger.write_string("UL")
    }
    // Ensure bytes literals have proper b"..." format
    Bytes(s) => {
      logger.write_string("b\"")
      logger.write_string(s)
      logger.write_string("\"")
    }
    // Ensure Int64 literals have L suffix
    Int64(s) => {
      logger.write_string(s)
      logger.write_string("L")
    }
    Byte(s) => {
      logger.write_string("b'")
      logger.write_string(s)
      logger.write_string("'")
    }
    Int(s) =>
      // Int literals don't need suffix as specified
      logger.write_string(s)
    UInt(s) => {
      logger.write_string(s)
      logger.write_string("U")
    }
    Float(s) => logger.write_string(s)
    Double(s) => logger.write_string(s)
    BigInt(s) => {
      logger.write_string(s)
      logger.write_string("N")
    }
  }
}

///|
fn print_label(label : @syntax.Label, logger : StringBuilder) -> Unit {
  logger.write_string(label.name)
}

///|
fn print_binder(binder : @syntax.Binder, logger : StringBuilder) -> Unit {
  // Don't print binder names that are just dots - these represent rest patterns
  if binder.name == "..." || binder.name == ".." {
    // Don't print anything for dot-only binder names to avoid duplication
    ()
  } else {
    logger.write_string(binder.name)
  }
}

///|
fn print_var(var_node : @syntax.Var, logger : StringBuilder) -> Unit {
  match var_node.name {
    Ident(name~) => logger.write_string(name)
    Dot(pkg~, id~) => {
      logger.write_string("@")
      logger.write_string(pkg)
      logger.write_string(".")
      logger.write_string(id)
    }
  }
}

///|
fn print_long_ident(ident : @syntax.LongIdent, logger : StringBuilder) -> Unit {
  match ident {
    Ident(name~) => logger.write_string(name)
    Dot(pkg~, id~) => {
      logger.write_string("@")
      logger.write_string(pkg)
      logger.write_string(".")
      logger.write_string(id)
    }
  }
}

///|
fn print_type_name(
  type_name : @syntax.TypeName,
  logger : StringBuilder,
) -> Unit {
  print_long_ident(type_name.name, logger)
}

///|
fn print_constr_name(
  constr_name : @syntax.ConstrName,
  logger : StringBuilder,
) -> Unit {
  logger.write_string(constr_name.name)
}

///|
fn print_constructor(
  constr : @syntax.Constructor,
  logger : StringBuilder,
) -> Unit {
  match constr.extra_info {
    TypeName(type_name) => {
      print_type_name(type_name, logger)
      logger.write_string("::")
      print_constr_name(constr.name, logger)
    }
    Package(pkg) => {
      logger.write_string("@")
      logger.write_string(pkg)
      logger.write_string(".")
      print_constr_name(constr.name, logger)
    }
    NoExtraInfo => print_constr_name(constr.name, logger)
  }
}

///|
fn print_type_var_binder(
  binder : @syntax.TypeVarBinder,
  logger : StringBuilder,
) -> Unit {
  logger.write_string(binder.name)
  if not(binder.constraints.is_empty()) {
    logger.write_string(" : ")
    print_list(binder.constraints, print_type_var_constraint, " + ", logger)
  }
}

///|
fn print_type_var_constraint(
  constraint : @syntax.TypeVarConstraint,
  logger : StringBuilder,
) -> Unit {
  print_long_ident(constraint.trait_, logger)
}