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

replpp.shaded.pprint.Walker.scala Maven / Gradle / Ivy

The newest version!
package replpp.shaded.pprint
import replpp.shaded.fansi

/**
  * A lazy AST representing pretty-printable text. Models `foo(a, b)`
  * `foo op bar`, and terminals `foo` in both lazy and eager forms
  */
sealed trait Tree
object Tree{

  /**
    * Foo(aa, bbb, cccc)
    */
  case class Apply(prefix: String,
                   body: Iterator[Tree]) extends Tree

  /**
    * LHS op RHS
    */
  case class Infix(lhs: Tree, op: String, rhs: Tree) extends Tree

  /**
    * "xyz"
    */
  case class Literal(body: String) extends Tree{
    val hasNewLine = body.exists(c => c == '\n' || c == '\r')
  }

  /**
    * x = y
    */
  case class KeyValue(key: String, value: Tree) extends Tree

  /**
    * xyz
    */
  case class Lazy(body0: Ctx => Iterator[String]) extends Tree

  case class Ctx(width: Int,
                 leftOffset: Int,
                 indentCount: Int,
                 indentStep: Int,
                 literalColor: fansi.Attrs,
                 applyPrefixColor: fansi.Attrs)
}

abstract class Walker{
  val tuplePrefix = "scala.Tuple"

  def additionalHandlers: PartialFunction[Any, Tree]
  def treeify(x: Any, escapeUnicode: Boolean, showFieldNames: Boolean): Tree = additionalHandlers.lift(x).getOrElse{
    x match{

      case null => Tree.Literal("null")
      case x: Boolean => Tree.Literal(x.toString)
      case x: Char =>
        val sb = new StringBuilder
        sb.append('\'')
        Util.escapeChar(x, sb, escapeUnicode)
        sb.append('\'')
        Tree.Literal(sb.toString)

      case x: Byte => Tree.Literal(x.toString)
      case x: Short => Tree.Literal(x.toString)
      case x: Int => Tree.Literal(x.toString)
      case x: Long => Tree.Literal(x.toString + "L")
      case x: Float => Tree.Literal(x.toString + "F")
      case x: Double => Tree.Literal(x.toString)
      case x: String =>
        // MP: adapted here: added ` || c == '\\'`
        // MP: upstream PR: https://github.com/com-lihaoyi/PPrint/pull/110
        if (x.exists(c => c == '\n' || c == '\r' || c == '\\')) Tree.Literal("\"\"\"" + x + "\"\"\"")
        else Tree.Literal(Util.literalize(x, escapeUnicode))

      case x: Symbol => Tree.Literal("'" + x.name)

      case x: scala.collection.Map[_, _] =>
        Tree.Apply(
          StringPrefix(x),
          x.iterator.flatMap { case (k, v) =>
            Seq(Tree.Infix(treeify(k, escapeUnicode, showFieldNames), "->", treeify(v, escapeUnicode, showFieldNames)))
          }
        )

      case x: Iterable[_] => Tree.Apply(StringPrefix(x), x.iterator.map(x => treeify(x, escapeUnicode, showFieldNames)))

      case None => Tree.Literal("None")

      case it: Iterator[_] =>
        // required since 2.13
        if (it.isEmpty)
          Tree.Literal("empty iterator")
        else
          Tree.Literal("non-empty iterator")

      case x: Array[_] => Tree.Apply("Array", x.iterator.map(x => treeify(x, escapeUnicode, showFieldNames)))

      case x: Product =>
        val className = x.getClass.getName
        if (x.productArity == 0) Tree.Lazy(ctx => Iterator(x.toString))
        else if(x.productArity == 2 && Util.isOperator(x.productPrefix)){
          Tree.Infix(
            treeify(x.productElement(0), escapeUnicode, showFieldNames),

            x.productPrefix,
            treeify(x.productElement(1), escapeUnicode, showFieldNames)
          )
        } else (className.startsWith(tuplePrefix), className.lift(tuplePrefix.length)) match{
          // leave out tuple1, so it gets printed as Tuple1(foo) instead of (foo)
          // Don't check the whole suffix, because of specialization there may be
          // funny characters after the digit
          case (true, Some('2' | '3' | '4' | '5' | '6' | '7' | '8' | '9')) =>
            Tree.Apply("", x.productIterator.map(x => treeify(x, escapeUnicode, showFieldNames)))

          case _ =>
            Tree.Apply(x.productPrefix, ProductSupport.treeifyProductElements(x, this, escapeUnicode, showFieldNames))
        }

      case x => Tree.Lazy(ctx =>
        Iterator(
          x.toString match{
            case null => "null"
            case s =>s
          }
        )
      )
    }
  }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy