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

loci.transmitter.Parser.scala Maven / Gradle / Ivy

The newest version!
package loci
package transmitter

import scala.collection.mutable
import scala.util.matching.Regex

object Parser {
  private val escape = """[\[\]\\:,]""".r
  private val unescape = """\\.""".r

  final class Deserializer private[Parser] (content: String, start: Int, end: Int) {
    private def parse(start: Int, end: Int): List[Deserializer] = {
      var depth = 0
      var first = start + 1
      var last = start + 1
      var escaped = false
      val buffer = mutable.ListBuffer.empty[Deserializer]

      if (start >= end - 1)
        throw new IllegalArgumentException("Malformed signature: "+
          "Expected '[...]' but found empty string")

      if (content(start) != '[' || content(end - 1) != ']')
        throw new IllegalArgumentException("Malformed signature: "+
          s"Expected '[...]' but found '${content.substring(start, end)}'")

      if (last < end - 1) {
        while (last < end - 1) {
          if (escaped)
            escaped = false
          else if (content(last) == '\\')
            escaped = true
          else if (content(last) == '[')
            depth += 1
          else if (content(last) == ']') {
            depth -= 1
            if (depth < 0)
              throw new IllegalArgumentException("Malformed signature: "+
                s"Superfluous ']' in ...${content.substring(start + 1, last + 1)}...")
          }
          else if (content(last) == ',' && depth == 0) {
            buffer += new Deserializer(content, first, last)
            first = last + 1
          }
          last += 1
        }

        if (depth != 0)
          throw new IllegalArgumentException("Malformed signature: "+
            s"Missing ']' in '${content.substring(start, end)}'")

        buffer += new Deserializer(content, first, last)
      }

      buffer.toList
    }

    @throws[IllegalArgumentException]("if the content cannot be parsed as tagged value")
    def asTag(tags: String*): (Int, Deserializer) = {
      var first = start
      var escaped = false

      while (first < end && (escaped || content(first) != ':')) {
        if (escaped)
          escaped = false
        else if (content(first) == '\\')
          escaped = true

        first += 1
      }

      if (first >= end)
        throw new IllegalArgumentException("Malformed signature: "+
          s"Expected tag name but found '${content.substring(start, end)}'")

      if (start >= first - 1)
        throw new IllegalArgumentException("Malformed signature: "+
          "Unexpected empty tag name")

      val tag = content.substring(start, first)
      val index = tags indexOf tag

      if (index == -1)
        throw new IllegalArgumentException("Malformed signature: "+
          s"Unexpected tag name '$tag' but expected one of ${tags.mkString("'", "', '", "'")}")

      index -> new Deserializer(content, first + 1, end)
    }

    @throws[IllegalArgumentException]("if the content cannot be parsed as a sequence of elements")
    def asElements(count: Int): List[Deserializer] = {
      val elements = parse(start, end)
      if (elements.size != count)
        throw new IllegalArgumentException("Malformed signature: "+
          s"Expected $count elements but found ${elements.size} elements in '${content.substring(start, end)}'")

      elements
    }

    @throws[IllegalArgumentException]("if the content cannot be parsed as a list")
    def asList: List[Deserializer] =
      parse(start, end)

    def asString: String = {
      val string = toString
      if (string == "[]")
        ""
      else
        unescape.replaceAllIn(
          string,
          matching => Regex.quoteReplacement(matching.matched(1).toString))
    }

    override def toString =
      content.substring(start, end)
  }

  def parse(content: String) = new Deserializer(content, 0, content.length)

  def apply(content: String) = parse(content)

  def tag(tag: String, value: Serializer) = new Serializer {
    if (tag.isEmpty)
      throw new IllegalArgumentException("Unexpected empty tag name")

    def toString(builder: StringBuilder) = {
      builder ++= escape(tag)
      builder += ':'
      value.toString(builder)
    }
  }

  def elements(elements: Serializer*) = new Serializer {
    def toString(builder: StringBuilder) = {
      var first = true
      builder += '['
      elements foreach { serializer =>
        if (first)
          first = false
        else
          builder += ','
        serializer.toString(builder)
      }
      builder += ']'
    }
  }

  def list(list: List[Serializer]) = elements(list: _*)

  def string(string: String) = new Serializer {
    def toString(builder: StringBuilder) = {
      if (string.isEmpty)
        builder ++= "[]"
      else
        builder ++= escape(string)
    }
  }

  private def escape(string: String): String =
    escape.replaceAllIn(
      string,
      matching => Regex.quoteReplacement(s"\\${matching.matched}"))

  abstract class Serializer private[Parser] {
    def toString(builder: StringBuilder): Unit

    override def toString: String = {
      val builder = new StringBuilder
      toString(builder)
      builder.toString
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy