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

commonMain.io.exoquery.pprint.Util.kt Maven / Gradle / Ivy

package io.exoquery.pprint

object Util {

  fun  concat(vararg isMatch: (() -> Iterator)) = ConcatIterator(isMatch.asSequence().map { it.invoke() }.iterator() /*(_())*/, { emptySequence().iterator() })

  /**
   * Basically a fast, efficient `.flatten` or `mkString` for nested iterators
   *
   * For some reason, the funault way of concatenation e.g.
   *
   * val middle = first ++ lastChildIter ++ sep ++ remaining
   *
   * Was throwing weird NullPointerExceptions I couldn't figure out =(
   *
   * Also, ++ didn't seem to be sufficiently lazy, so it was forcing
   * things earlier than it really needed to. It isn't documented anywhere
   * how lazy it's meant to be, whereas `ConcatIterator` here is obviously
   * lazy and won't even evaluate each iterator until you ask it to
   */
  class ConcatIterator(val it0: Iterator>, val joiner: () -> Iterator): Iterator {
    private var head: Iterator? = null
    private var count = 0

    private tailrec fun check(): Boolean =
      if (head != null && head?.hasNext()!!) true
      else if (!it0.hasNext()) false
      else {
        if (count % 2 == 0) head = it0.next()
        else head = joiner()
        count += 1

        check()
      }

    override fun hasNext() = check()

    /*
    There is an inherent assumption in this class that hasNext() will always be called
    and the it0.hasNext() will always return false when the `head` is null. If `next()`
    is called afterward a null-pointer exception can be thrown. The only way to solve
    this is to create a state such that:
    sealed trait State
    data class CheckTrue(it: Iterator)
    object CheckFalse
    Then when check() would be called here and it does CheckFalse() then an exception
    is thrown. Doing all of these things however likely imposes some performance penanties
    unless transparent objects are used. Should look into this.
     */
    override fun next():T {
      check()
      return head?.next() ?: throw RuntimeException("Concat iterator error, head was null")
    }
  }

  fun isOperator(ident: String): Boolean {
    return (ident.length > 0) && (when (ident[0]) {
      '<' -> true
      '~' -> true
      '!' -> true
      '@' -> true
      '#' -> true
      '%' -> true
      '^' -> true
      '*' -> true
      '+' -> true
      '-' -> true
      /*'<' | */
      '>' -> true
      '?' -> true
      ':' -> true
      '=' -> true
      '&' -> true
      '|' -> true
      '/' -> true
      '\\' -> true
      else -> false
    })
  }

  fun escapeChar(c: Char, sb: StringBuilder, unicode: Boolean = true, makeHexString: (Char) -> String) = when (c) {

    // Have a look here: https://www.oreilly.com/library/view/android-development-with/9781787123687/edad3c06-152f-41a4-8080-0db1eb395680.xhtml
    // for a list of escape sequences in kotlin

    '\t' -> sb.append("\\t") // Tabulator
    '\b' -> sb.append("\\b") // Backspace
    '\n' -> sb.append("\\n") // Newline
    '\r' -> sb.append("\\r") // Carriage return
    '\'' -> sb.append("\\\'") // Quote
    '"' -> sb.append("\\\"")  // Double quote
    '\\' -> sb.append("\\\\") // Slash
    '\$' -> sb.append("\\$") // Dollar character

    // '\u' -> sb.append("\\$") // not legal and I don't think is needed
    //'\f' -> sb.append("\\f")  // no such escape sequence in kotlin?

    else ->
      if (c < ' ' || (c > '~' && unicode)) sb.append(makeHexString(c))
      else sb.append(c)
  }

  fun literalize(s: String, unicode: Boolean = true, makeHexString: (Char) -> String): String =
    literalize(s.toCharArray(), unicode, makeHexString)

  fun literalize(s: CharArray, unicode: Boolean = true, makeHexString: (Char) -> String): String {
    val sb = StringBuilder()
    sb.append('"')
    var i = 0
    val len = s.size
    while (i < len) {
      Util.escapeChar(s[i], sb, unicode, makeHexString)
      i += 1
    }
    sb.append('"')

    return sb.toString()
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy