All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.scrooge.AST.Identifier.scala Maven / Gradle / Ivy

The newest version!
package com.twitter.scrooge.ast

import scala.collection.mutable
import com.twitter.scrooge.frontend.ScroogeInternalException

sealed abstract class Identifier extends IdNode {
  // It was intentional not to override toString. Instead, use
  // "fullName" to indicate its purpose.
  def fullName: String

  def toCamelCase: Identifier
  def toTitleCase: Identifier
  def toUpperCase: Identifier
  def toLowerCase: Identifier

  // to prevent accidental use of Identifier as String
  private[scrooge] def +(str: String): String =
    throw new ScroogeInternalException("do not use \"+\" operation on Identifiers")
}

object Identifier {
  // constructor
  def apply(str: String): Identifier = {
    assert(!str.isEmpty)
    val ids = str.split("\\.")
    if (ids.size == 1)
      SimpleID(ids.head)
    else
      QualifiedID(ids)
  }

  def toTitleCase(str: String): String = toCamelCase(str, true)

  /**
   * convert string to camel case, with the following fine print:
   *   - leading underscores are preserved
   *   - internal underscores are removed. Character following an underscore
   *     is converted to upper case.
   *   - first character (non underscore char) is upper case if
   *     firstCharUp is true, lower case if false
   *   - first character of the second and following parts (text between underscores)
   *     is always in upper case
   *   - if a part is all upper case it is converted to lower case (except for first character),
   *     in other cases case is preserved
   *
   *   Examples: (original, camel case, title case)
   *     (gen_html_report, genHtmlReport, GenHtmlReport)
   *     (GEN_HTML_REPORT, genHtmlReport, GenHtmlReport)
   *     (Gen_HTMLReport, genHTMLReport, GenHTMLReport)
   *     (Gen_HTML_Report, genHtmlReport, GenHtmlReport)
   *     (GENHTMLREPORT, genhtmlreport, Genhtmlreport)
   *     (genhtmlreport, genhtmlreport, Genhtmlreport)
   *     (genHtmlReport, genHtmlReport, GenHtmlReport)
   *     (genHTMLReport, genHTMLReport, GenHtmlReport)
   *     (_genHtmlReport, _genHtmlReport, _GenHtmlReport)
   */
  def toCamelCase(str: String, firstCharUp: Boolean = false): String = {
    str.takeWhile(_ == '_') + str.
      split('_').
      filterNot(_.isEmpty).
      zipWithIndex.map { case (part, ind) =>
        val first = if (ind == 0 && !firstCharUp) part(0).toLower else part(0).toUpper
        val isAllUpperCase = part.forall { c => c.isUpper || !c.isLetter }
        val rest = if (isAllUpperCase) part.drop(1).toLowerCase else part.drop(1)
        new mutable.StringBuilder(part.size).append(first).append(rest)
      }.
      mkString
  }
}

case class SimpleID(name: String, origName: Option[String] = None) extends Identifier {
  assert(!name.contains(".") && !name.isEmpty) // name is a simple string
  val fullName: String = name

  val originalName = origName.getOrElse(fullName)

  def toCamelCase = SimpleID(Identifier.toCamelCase(name), origName = Some(originalName))
  def toTitleCase = SimpleID(Identifier.toTitleCase(name), origName = Some(originalName))
  def toUpperCase = SimpleID(name.toUpperCase, origName = Some(originalName))
  def toLowerCase = SimpleID(name.toLowerCase, origName = Some(originalName))

  // append and prepend only available for SimpleID
  // To encourage correct usage of SimpleID, we intentionally don't use implicit
  // string conversions
  def append(other: String): SimpleID = {
    assert(!other.isEmpty && !other.contains("."))
    SimpleID(name + other)
  }

  def prepend(other: String): SimpleID = {
    assert(!other.isEmpty && !other.contains("."))
    SimpleID(other + name)
  }

  def addScope(scope: Identifier): QualifiedID =
    QualifiedID(scope match {
      case SimpleID(s, _) => Seq(s, this.name)
      case QualifiedID(names) => names :+ name
    })
}

case class QualifiedID(names: Seq[String]) extends Identifier {
  assert(names.size >= 2) // at least a scope and a name
  assert(!names.exists(_.isEmpty))
  val fullName: String = names.mkString(".")

  // case conversion only happens on the last id
  def toCamelCase =
    QualifiedID(names.dropRight(1) :+ Identifier.toCamelCase(names.last))
  def toTitleCase =
    QualifiedID(names.dropRight(1) :+ Identifier.toTitleCase(names.last))
  def toUpperCase =
    QualifiedID(names.dropRight(1) :+ names.last.toUpperCase)
  def toLowerCase =
    QualifiedID(names.dropRight(1) :+ names.last.toLowerCase)

  def head: SimpleID = SimpleID(names.head)
  def tail: Identifier = Identifier(names.tail.mkString("."))

  def qualifier: Identifier = Identifier(names.dropRight(1).mkString("."))
  def name: SimpleID = SimpleID(names.last)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy