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

com.rojoma.json.v3.io.JValueGenerator.scala Maven / Gradle / Ivy

The newest version!
package com.rojoma.json.v3
package io

import scala.collection.mutable.LinkedHashMap

import ast._

import JValueGenerator._

sealed abstract class JValueGenerator {
  def apply(event: JsonEvent): Result
}

object JValueGenerator {
  sealed abstract class Result
  sealed abstract class SuccessfulResult extends Result
  case class Value(value: JValue) extends SuccessfulResult
  case class More(newState: JValueGenerator) extends SuccessfulResult
  sealed abstract class Error extends Result {
    def position: Position
  }
  case class UnknownIdentifier(identifier: String, position: Position) extends Error
  case class BadParse(event: JsonEvent, position: Position) extends Error

  val newGenerator: JValueGenerator = JValueGeneratorImpl.AwaitingStartOfDatum
}

private[io] object JValueGeneratorImpl {
  final case class Field(key: String, value: JValue)

  val jtrue = JBoolean.canonicalTrue
  val jfalse = JBoolean.canonicalFalse

  sealed abstract class ChildState extends JValueGenerator {
    protected def parent: ParentState

    protected def result(v: JValue): Result =
      if(parent == null) Value(v)
      else parent.add(v)

    protected def enparent(s: String) = if(parent == null) s else s + " :: " + parent

    def jObject(fields: Vector[Field]) = {
      val map = new LinkedHashMap[String, JValue]
      val it = fields.iterator
      while(it.hasNext) {
        val f = it.next()
        map(f.key) = f.value
      }
      JObject(map)
    }
  }

  sealed abstract class ParentState extends ChildState { // a child which can also be a parent
    def add(value: JValue): Result

    protected def commonHandle(event: JsonEvent): Result = event match {
      case StartOfObjectEvent() => More(new AwaitingKeyOrEndOfObject(Vector.empty, this))
      case StartOfArrayEvent() => More(new AwaitingElementOrEndOfArray(Vector.empty, this))
      case StringEvent(s) => add(JString(s))
      case NumberEvent(n) => add(JNumber.unsafeFromString(n))
      case IdentifierEvent("true") => add(jtrue)
      case IdentifierEvent("false") => add(jfalse)
      case IdentifierEvent("null") => add(JNull)
      case IdentifierEvent(other) => UnknownIdentifier(other, event.position)
      case other => BadParse(other, other.position)
    }
  }

  object AwaitingStartOfDatum extends JValueGenerator {
    def apply(event: JsonEvent) = event match {
      case StartOfObjectEvent() => topLevelObject
      case StartOfArrayEvent() => topLevelArray
      case StringEvent(s) => Value(JString(s))
      case NumberEvent(n) => Value(JNumber.unsafeFromString(n))
      case IdentifierEvent("true") => Value(jtrue)
      case IdentifierEvent("false") => Value(jfalse)
      case IdentifierEvent("null") => Value(JNull)
      case IdentifierEvent(other) => UnknownIdentifier(other, event.position)
      case other => BadParse(other, other.position)
    }

    val topLevelObject = More(new AwaitingKeyOrEndOfObject(Vector.empty, null))
    val topLevelArray = More(new AwaitingElementOrEndOfArray(Vector.empty, null))

    override def toString = "AwaitingStartOfDatum"
  }

  class AwaitingElementOrEndOfArray(val elems: Vector[JValue], val parent: ParentState) extends ParentState {
    def apply(event: JsonEvent) = event match {
      case EndOfArrayEvent() => result(JArray(elems))
      case _ => commonHandle(event)
    }

    def add(v: JValue): Result =
      More(new AwaitingElementOrEndOfArray(elems :+ v, parent))

    override def toString = enparent("AwaitingElementOrEndOfArray(" + JArray(elems) + ")")
    override def hashCode = elems.hashCode + parent.##
    override def equals(o: Any) = o match {
      case that: AwaitingElementOrEndOfArray => this.elems == that.elems && this.parent == that.parent
      case _ => false
    }
  }

  class AwaitingKeyOrEndOfObject(val fields: Vector[Field], val parent: ParentState) extends ChildState {
    def apply(event: JsonEvent) = event match {
      case FieldEvent(name) => More(new AwaitingValue(name, fields, parent))
      case EndOfObjectEvent() => result(jObject(fields))
      case other => BadParse(other, other.position)
    }

    override def toString = enparent("AwaitingKeyOrEndOfObject(" + jObject(fields) + ")")
    override def hashCode = fields.hashCode + parent.##
    override def equals(o: Any) = o match {
      case that: AwaitingKeyOrEndOfObject => this.fields == that.fields && this.parent == that.parent
      case _ => false
    }
  }

  class AwaitingValue(val field: String, val fields: Vector[Field], val parent: ParentState) extends ParentState {
    def apply(event: JsonEvent) = commonHandle(event)

    def add(v: JValue): Result =
      More(new AwaitingKeyOrEndOfObject(fields :+ Field(field, v), parent))

    override def toString = enparent("AwaitingValue(" + JString(field) + " : " + jObject(fields) + ")")
    override def hashCode = field.hashCode + fields.hashCode + parent.##
    override def equals(o: Any) = o match {
      case that: AwaitingValue => this.field == that.field && this.fields == that.fields && this.parent == that.parent
      case _ => false
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy