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

os.serial.internal.FromString.scala Maven / Gradle / Ivy

The newest version!
// Copyright 2013, 2014  Optersoft Inc. - www.optersoft.com

package os.serial

import scala.collection.mutable.HashMap
import java.lang.Long
import scala.reflect._

// http://eclipsesource.com/blogs/2013/04/18/minimal-json-parser-for-java/

object FromString {

  def apply[S <: Serial](string: String)(implicit tag: ClassTag[S]): S =
    (new FromString(string)).run().asInstanceOf[S]

  abstract class Frame {

    def obj: Any
    var next: Frame = _
    var key: String = _

    def value(obj: Any)

  }

//  private class MirrorFrame(val mirror: Mirror) extends Frame {
//
//    val obj = mirror.newInstance
//
//    def value(value: Any) {
//
//      mirror.find(key).foreach(_.set(obj, value))
//      key = null
//
//    }
//
//    override def toString = s"Frame[${mirror.clazz.getSimpleName()}]"
//
//  }

  private class MapFrame extends Frame {

    var obj = Map.empty[Any, Any]

    def value(value: Any) {
      obj = obj + (key -> value)
      key = null
    }
  }

  private class SeqFrame extends Frame {

    var obj = Seq.empty[Any]
    key = ""

    def value(value: Any) {
      obj = obj :+ value

    }

  }

  private class ClassFrame(clazz: Class[_]) extends Frame {

    val obj = ""

    def value(value: Any) {

    }
  }
}

class FromString(string: String) {

  import FromString._

  private var index = 0
  private var pointer = 0

  private var frame: Frame = _

  def run() = {

    while (index < string.size) {

      def isDelimiter(c: Char) = c == ' ' || c == '\n' || c == ',' || c == '\r' || c == '\t' || c == '}' || c == ']'

      next match {
        case '{' => newObject()
        case '}' =>
          removeFrame()

        case '"' =>
          if (isType(index)) {
            while (index < string.size &&
              (string.charAt(index) != ',' && string.charAt(index) != '}')) { index += 1 }
          } else {
            if (frame.key == null) {
              val mark = index
              while (next != '"') {}
              frame.key = string.substring(mark, index - 1)
            } else {
              frame.value(parseString)
            }
          }
        case 't' =>
          index += 3; frame.value(true)
        case 'f' =>
          index += 4; frame.value(false)
        case 'n' => index += 3
        case ':' =>
        case '[' => addFrame(new SeqFrame)
        case ']' => removeFrame
        case c if Character.isDigit(c) || c == '-' =>
          frame.value(parseValue(c))
        case c if isDelimiter(c) =>
        case c => fail("unknown token " + c)
      }

    }

    if (frame == null) null
    else
      frame.obj

  }

  def next = {
    val char = string.charAt(index)
    index += 1
    char
  }

  def back() { index -= 1 }

  def mark = pointer = index

  def substring = string.substring(pointer, index - 1)

  def newObject() {

//    addFrame(
//      findType(index) match {
//        case None =>
//          new MapFrame
//        //        val clazz = stack.head.attribute.target
//        //        Reflect(clazz.asInstanceOf[Class[Reflect]])
//        case Some(tpe) =>
//          val code = tpe.substring(tpe.size - 6)
//          val id = code
//          Reflect(id) match {
//            case None => throw new ReflectError(s"Not found class for id: $id")
//            case Some(mirror) => new MirrorFrame(mirror)
//          }
//      })
  }

  private def addFrame(newFrame: Frame) {

    if (frame == null)
      frame = newFrame
    else {
      newFrame.next = frame
      frame = newFrame
    }

  }

  private def removeFrame() {
    if (frame.next != null) {
      val obj = frame.obj
      frame = frame.next
      frame.value(obj)
    }
  }

  private[serial] def findType(start: Int): Option[String] = {

    var i = start
    var stack = 0
    var tpe = false

    while (i < string.size) {
      string.charAt(i) match {
        case '{' => stack += 1
        case '}' => stack -= 1
        case '"' =>

          val mark = i
          i += 1; while (i < string.size && string.charAt(i) != '"') { i += 1 }

          if (tpe) {
            val result = string.substring(mark + 1, i)
            return Some(result)
          } else if (stack == 0 && isType(mark + 1))
            tpe = true

        case _ =>
      }

      i += 1
    }

    None
  }

  private[serial] def isType(i: Int) = string.charAt(i) == 'T' && string.charAt(i + 1) == '"'

  private def parseString(): String = {

    def unquote(base: String): String = {
      val s = new java.lang.StringBuilder(base)
      var c = '\\'
      while (c != '"') {
        if (c == '\\') {
          next match {
            case '"' => s.append('"')
            case '\\' => s.append('\\')
            case '/' => s.append('/')
            case 'b' => s.append('\b')
            case 'f' => s.append('\f')
            case 'n' => s.append('\n')
            case 'r' => s.append('\r')
            case 't' => s.append('\t')
            case 'u' =>
              val chars = Array(next, next, next, next)
              val codePoint = Integer.parseInt(new String(chars), 16)
              s.appendCodePoint(codePoint)
            case _ => s.append('\\')
          }
        } else s.append(c)
        c = next
      }
      s.toString
    }

    mark
    var c = next
    while (c != '"') {
      if (c == '\\') {
        return unquote(substring)
      }
      c = next
    }
    substring
  }

  private def parseValue(first: Char) = {
    var wasInt = true
    var doubleVal = false
    val s = new StringBuilder
    s.append(first)
    while (wasInt) {
      val c = next
      if (c == '.' || c == 'e' || c == 'E') {
        doubleVal = true
        s.append(c)
      } else if (!(Character.isDigit(c) || c == '.' || c == 'e' || c == 'E' || c == '-')) {
        wasInt = false
        back
      } else s.append(c)
    }
    val value = s.toString
    //if (doubleVal)  //parseDouble(value)
    //else 
    Integer.parseInt(value)

  }

  private[serial] def parseDouble(s: String) = {
    val d = BigDecimal(s)
    //if (d == BrokenDouble) error("Error parsing 2.2250738585072012e-308")
    //else 
    d.doubleValue
  }

  def fail(msg: String) {

    val sb = new StringBuilder
    sb ++= msg
    sb ++= ": "
    val start = if (index < 10) 0 else index - 10
    sb ++= string.substring(start, index - 1)
    sb += '>'
    sb += string.charAt(index - 1)
    sb += '<'
    sb ++= string.substring(index).take(10)

    throw new Exception(sb.toString)
  }

}

class ParserException(msg: String) extends RuntimeException(msg)




© 2015 - 2025 Weber Informatics LLC | Privacy Policy