
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