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

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

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

import JsonEventGenerator._
import JsonEventGeneratorImpl._

sealed abstract class JsonEventGenerator private[io] (val fieldCache: FieldCache, protected val stack: Stack) {
  def apply(token: JsonToken): Result
  protected def name: String
  protected val depth: Int = if(stack eq null) 0 else stack.depth + 1

  def parse(token: JsonToken): SuccessfulResult = apply(token) match {
    case r: SuccessfulResult => r
    case e: Error => throwError(e)
  }

  def endOfInput(position: Position): EndResult = {
    if(atTopLevel) Finished
    else Unfinished(position)
  }

  def endOfInput(row: Int, column: Int): EndResult = endOfInput(Position(row, column))

  def finish(position: Position): SuccessfulEndResult = {
    endOfInput(position) match {
      case r: SuccessfulEndResult => r
      case e: EndError => throwError(e)
    }
  }

  def finish(row: Int, column: Int): SuccessfulEndResult = finish(Position(row, column))

  def atTopLevel: Boolean = (stack eq null) && this.isInstanceOf[AwaitingDatum]

  override def equals(o: Any): Boolean = o match {
    case that: JsonEventGenerator => locallySame(that) && this.stack == that.stack
    case _ => false
  }

  override def hashCode: Int = localHashCode ^ stack.hashCode

  override def toString = {
    val sb = new StringBuilder("JsonEventGenerator(").append(name)
    var it = stack
    while(it ne null) {
      sb.append(',').append(it.name)
      it = it.stack
    }
    sb.append(')').mkString
  }

  protected def localHashCode: Int = getClass.hashCode
  protected def locallySame(that: JsonEventGenerator): Boolean = this.getClass == that.getClass

  protected def event(ev: JsonEvent, newState: JsonEventGenerator): Result = {
    val trueNewState = if(newState eq null) newGenerator(fieldCache) else newState
    Event(ev, trueNewState)
  }

  protected def more(newState: JsonEventGenerator): Result =
    More(newState)

  protected def error(got: JsonToken, expected: String): Result =
    UnexpectedToken(got, expected)
}

object JsonEventGenerator {
  sealed trait AnyError

  sealed abstract class Result
  sealed abstract class SuccessfulResult extends Result
  sealed abstract class Error extends Result with AnyError

  sealed trait EndResult
  sealed trait SuccessfulEndResult extends EndResult
  sealed trait EndError extends EndResult with AnyError

  case class More(newState: JsonEventGenerator) extends SuccessfulResult
  case class Event(event: JsonEvent, newState: JsonEventGenerator) extends SuccessfulResult

  case object Finished extends SuccessfulEndResult

  case class UnexpectedToken(token: JsonToken, expected: String) extends Error with EndError
  case class Unfinished(position: Position) extends EndError

  val newGenerator: JsonEventGenerator = newGenerator(IdentityFieldCache)
  def newGenerator(fieldCache: FieldCache): JsonEventGenerator = new AwaitingDatum(fieldCache, null)

  def throwError(e: AnyError): Nothing = e match {
    case UnexpectedToken(token, expected) => throw new JsonUnexpectedToken(token, expected)
    case Unfinished(pos) => throw new JsonParserEOF(pos)
  }
}

private[io] object JsonEventGeneratorImpl {
  type Stack = JsonEventGenerator

  class AwaitingDatum(fc: FieldCache, s: Stack) extends JsonEventGenerator(fc, s) {
    def apply(token: JsonToken) = token match {
      case TokenOpenBrace() =>
        event(StartOfObjectEvent()(token.position), new AwaitingFieldNameOrEndOfObject(fieldCache, stack))
      case TokenOpenBracket() =>
        event(StartOfArrayEvent()(token.position), new AwaitingEntryOrEndOfArray(fieldCache, stack))
      case TokenIdentifier(text) =>
        event(IdentifierEvent(text)(token.position), stack)
      case TokenNumber(number) =>
        event(NumberEvent(number)(token.position), stack)
      case TokenString(string) =>
        event(StringEvent(string)(token.position), stack)
      case _ =>
        error(token, "datum")
    }

    def name = "AwaitingDatum"
  }

  class AwaitingEntryOrEndOfArray(fc: FieldCache, s: Stack) extends JsonEventGenerator(fc, s) {
    def apply(token: JsonToken) = token match {
      case TokenOpenBrace() =>
        event(StartOfObjectEvent()(token.position), new AwaitingFieldNameOrEndOfObject(fieldCache, new AwaitingCommaOrEndOfArray(fieldCache, stack)))
      case TokenOpenBracket() =>
        event(StartOfArrayEvent()(token.position), new AwaitingEntryOrEndOfArray(fieldCache, new AwaitingCommaOrEndOfArray(fieldCache, stack)))
      case TokenIdentifier(text) =>
        event(IdentifierEvent(text)(token.position), new AwaitingCommaOrEndOfArray(fieldCache, stack))
      case TokenNumber(number) =>
        event(NumberEvent(number)(token.position), new AwaitingCommaOrEndOfArray(fieldCache, stack))
      case TokenString(string) =>
        event(StringEvent(string)(token.position), new AwaitingCommaOrEndOfArray(fieldCache, stack))
      case TokenCloseBracket() =>
        event(EndOfArrayEvent()(token.position), stack)
      case _ =>
        error(token, "datum or end of array")
    }

    def name = "AwaitingEntryOrEndOfArray"
  }

  class AwaitingCommaOrEndOfArray(fc: FieldCache, s: Stack) extends JsonEventGenerator(fc, s) {
    def apply(token: JsonToken) = token match {
      case TokenComma() =>
        more(new AwaitingDatum(fieldCache, new AwaitingCommaOrEndOfArray(fieldCache, stack)))
      case TokenCloseBracket() =>
        event(EndOfArrayEvent()(token.position), stack)
      case _ =>
        error(token, "comma or end of array")
    }

    def name = "AwaitingCommaOrEndOfArray"
  }

  class AwaitingFieldNameOrEndOfObject(fc: FieldCache, s: Stack) extends JsonEventGenerator(fc, s) {
    def apply(token: JsonToken) = token match {
      case TokenCloseBrace() =>
        event(EndOfObjectEvent()(token.position), stack)
      case TokenString(text) =>
        event(FieldEvent(fieldCache(text, depth))(token.position), new AwaitingKVSep(fieldCache, new AwaitingCommaOrEndOfObject(fieldCache, stack)))
      case TokenIdentifier(text) =>
        event(FieldEvent(fieldCache(text, depth))(token.position), new AwaitingKVSep(fieldCache, new AwaitingCommaOrEndOfObject(fieldCache, stack)))
      case _ =>
        error(token, "field name or end of object")
    }

    def name = "AwaitingFieldNameOrEndOfObject"
  }

  class AwaitingFieldName(fc: FieldCache, s: Stack) extends JsonEventGenerator(fc, s) {
    def apply(token: JsonToken) = token match {
      case TokenString(text) =>
        event(FieldEvent(fieldCache(text, depth))(token.position), new AwaitingKVSep(fieldCache, stack))
      case TokenIdentifier(text) =>
        event(FieldEvent(fieldCache(text, depth))(token.position), new AwaitingKVSep(fieldCache, stack))
      case _ =>
        error(token, "field name")
    }

    def name = "AwaitingFieldName"
  }

  class AwaitingKVSep(fc: FieldCache, s: Stack) extends JsonEventGenerator(fc, s) {
    def apply(token: JsonToken) = token match {
      case TokenColon() =>
        more(new AwaitingDatum(fieldCache, stack))
      case _ =>
        error(token, "colon")
    }

    def name = "AwaitingKVSep"
  }

  class AwaitingCommaOrEndOfObject(fc: FieldCache, s: Stack) extends JsonEventGenerator(fc, s) {
    def apply(token: JsonToken) = token match {
      case TokenComma() =>
        more(new AwaitingFieldName(fieldCache, new AwaitingCommaOrEndOfObject(fieldCache, stack)))
      case TokenCloseBrace() =>
        event(EndOfObjectEvent()(token.position), stack)
      case _ =>
        error(token, "comma or end of object")
    }

    def name = "AwaitingCommaOrEndOfObject"
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy