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

io.dylemma.spac.json.JsonEvent.scala Maven / Gradle / Ivy

There is a newer version: 0.12.1
Show newest version
package io.dylemma.spac
package json

import cats.Show
import cats.data.Chain

/** ADT for tokens in a JSON stream.
  *
  * @group event
  */
sealed trait JsonEvent extends HasLocation {
	import JsonEvent._

	def isObjectStart: Boolean = false
	def isObjectEnd: Boolean = false
	def isArrayStart: Boolean = false
	def isArrayEnd: Boolean = false
	def asFieldStart: Option[FieldStart] = None
	def asFieldEnd: Option[FieldEnd] = None
	def asIndexStart: Option[IndexStart] = None
	def asIndexEnd: Option[IndexEnd] = None

	def asStackPush: Option[JsonStackElem] = None
	def asStackPop: Option[JsonStackPop] = None
	def asValueEvent: Option[JsonValueEvent] = None

	def asBool: Option[JBool] = None
	def asLong: Option[JLong] = None
	def asDouble: Option[JDouble] = None
	def asString: Option[JString] = None
	def asNull: Option[JNull] = None

	def showRawJson: String
}

/** Subset of JsonEvents that constitute a "context stack push".
  *
  * @group event
  */
sealed trait JsonStackElem extends JsonEvent {
	override def asStackPush = Some(this)
}

/** Subset of JsonEvents that constitute a "context stack pop".
  *
  * @group event
  */
sealed trait JsonStackPop extends JsonEvent {
	override def asStackPop = Some(this)
}

/** Subset of JsonEvents that represent a primitive values
  *
  * @group event
  */
sealed trait JsonValueEvent extends JsonEvent {
	def valueAsString: String
	override def asValueEvent = Some(this)
}

/** @group event */
object JsonEvent {

	implicit val jsonStackLike: StackLike[JsonEvent, JsonStackElem] = (e: JsonEvent) => {
		e.asStackPush.map { push =>
			if (push.isObjectStart || push.isArrayStart) {
				// `{` and `[` count as part of the context that they open
				ContextPush(ContextTrace(Chain.one(e.location -> e)), push).beforeInput
			} else {
				// index and field starts are excluded from contexts that they open
				ContextPush(ContextTrace(Chain.one(e.location -> e)), push).afterInput
			}
		} orElse e.asStackPop.map { pop =>
			if (pop.isObjectEnd || pop.isArrayEnd) {
				// `}` and `]` count as part of the context that they close
				ContextPop.afterInput
			} else {
				// index and field ends are excluded from the contexts that they close
				ContextPop.beforeInput
			}
		} getOrElse {
			StackInterpretation.NoChange
		}
	}

	trait ObjectStart extends JsonStackElem {
		override def isObjectStart = true
		override def toString = "ObjectStart"
		def showRawJson = "{"
	}
	object ObjectStart {
		def unapply(e: JsonEvent): Boolean = e.isObjectStart
		def apply(loc: ContextLocation): ObjectStart = new Impl(loc)

		private class Impl(val location: ContextLocation) extends ObjectStart
	}

	trait ObjectEnd extends JsonStackPop {
		override def isObjectEnd = true
		override def toString = "ObjectEnd"
		def showRawJson = "}"
	}
	object ObjectEnd {
		def unapply(e: JsonEvent): Boolean = e.isObjectEnd
		def apply(loc: ContextLocation): ObjectEnd = new Impl(loc)

		private class Impl(val location: ContextLocation) extends ObjectEnd
	}

	trait FieldStart extends JsonStackElem {
		def fieldName: String
		override def asFieldStart = Some(this)
		override def toString = s"FieldStart($fieldName)"
		def showRawJson = s"$fieldName:"
	}
	object FieldStart {
		def unapply(e: JsonEvent): Option[String] = e.asFieldStart.map(_.fieldName)
		def apply(fieldName: String, loc: ContextLocation): FieldStart = new Impl(fieldName, loc)

		private class Impl(val fieldName: String, val location: ContextLocation) extends FieldStart
	}

	trait FieldEnd extends JsonStackPop {
		def fieldName: String
		override def asFieldEnd = Some(this)
		override def toString = s"FieldEnd($fieldName)"
		def showRawJson = ""
	}
	object FieldEnd {
		def unapply(e: JsonEvent): Option[String] = e.asFieldEnd.map(_.fieldName)
		def apply(fieldName: String, loc: ContextLocation): FieldEnd = new Impl(fieldName, loc)

		private class Impl(val fieldName: String, val location: ContextLocation) extends FieldEnd
	}

	trait ArrayStart extends JsonStackElem {
		override def isArrayStart = true
		override def toString = "ArrayStart"
		def showRawJson = "["
	}
	object ArrayStart {
		def unapply(e: JsonEvent): Boolean = e.isArrayStart
		def apply(loc: ContextLocation): ArrayStart = new Impl(loc)

		private class Impl(val location: ContextLocation) extends ArrayStart
	}

	trait ArrayEnd extends JsonStackPop {
		override def isArrayEnd = true
		override def toString = "ArrayEnd"
		def showRawJson = "]"
	}
	object ArrayEnd {
		def unapply(e: JsonEvent): Boolean = e.isArrayEnd
		def apply(loc: ContextLocation): ArrayEnd = new Impl(loc)

		private class Impl(val location: ContextLocation) extends ArrayEnd
	}

	trait IndexStart extends JsonStackElem {
		def index: Int
		override def asIndexStart = Some(this)
		override def toString = s"IndexStart($index)"
		def showRawJson = ""
	}
	object IndexStart {
		def unapply(e: JsonEvent): Option[Int] = e.asIndexStart.map(_.index)
		def apply(index: Int, loc: ContextLocation): IndexStart = new Impl(index, loc)

		private class Impl(val index: Int, val location: ContextLocation) extends IndexStart
	}

	trait IndexEnd extends JsonStackPop {
		def index: Int
		override def asIndexEnd = Some(this)
		override def toString = s"IndexEnd($index)"
		def showRawJson = ""
	}
	object IndexEnd {
		def unapply(e: JsonEvent): Option[Int] = e.asIndexEnd.map(_.index)
		def apply(index: Int, loc: ContextLocation): IndexEnd = new Impl(index, loc)

		private class Impl(val index: Int, val location: ContextLocation) extends IndexEnd
	}

	trait JBool extends JsonValueEvent {
		def booleanValue: Boolean
		def valueAsString = String.valueOf(booleanValue)
		override def asBool = Some(this)
		override def toString = s"JBool($booleanValue)"
		def showRawJson = valueAsString
	}
	object JBool {
		def unapply(e: JsonEvent): Option[Boolean] = e.asBool.map(_.booleanValue)
		def apply(b: Boolean, loc: ContextLocation): JBool = new Impl(b, loc)

		private class Impl(val booleanValue: Boolean, val location: ContextLocation) extends JBool
	}

	trait JLong extends JsonValueEvent {
		def longValue: Long
		def valueAsString = String.valueOf(longValue)
		override def asLong = Some(this)
		override def toString = s"JLong($longValue)"
		def showRawJson = valueAsString
	}
	object JLong {
		def unapply(e: JsonEvent): Option[Long] = e.asLong.map(_.longValue)
		def apply(n: Long, loc: ContextLocation): JLong = new Impl(n, loc)

		private class Impl(val longValue: Long, val location: ContextLocation) extends JLong
	}

	trait JDouble extends JsonValueEvent {
		def doubleValue: Double
		def valueAsString = String.valueOf(doubleValue)
		override def asDouble = Some(this)
		override def toString = s"JDouble($doubleValue)"
		def showRawJson = valueAsString
	}
	object JDouble {
		def unapply(e: JsonEvent): Option[Double] = e.asDouble.map(_.doubleValue)
		def apply(n: Double, loc: ContextLocation): JDouble = new Impl(n, loc)

		private class Impl(val doubleValue: Double, val location: ContextLocation) extends JDouble
	}

	trait JString extends JsonValueEvent {
		def stringValue: String
		def valueAsString = stringValue
		override def asString = Some(this)
		override def toString = s"JString($stringValue)"
		def showRawJson = stringValue.replaceAll("\"", "\\\"")
	}
	object JString {
		def unapply(e: JsonEvent): Option[String] = e.asString.map(_.stringValue)
		def apply(s: String, loc: ContextLocation): JString = new Impl(s, loc)

		private class Impl(val stringValue: String, val location: ContextLocation) extends JString
	}

	trait JNull extends JsonValueEvent {
		def valueAsString = "null"
		override def asNull = Some(this)
		override def toString = "JNull"
		def showRawJson = "null"
	}
	object JNull {
		def unapply(e: JsonEvent): Boolean = e.asNull.isDefined
		def apply(loc: ContextLocation): JNull = new Impl(loc)

		private class Impl(val location: ContextLocation) extends JNull
	}

	implicit val showJsonEventAsRawJson: Show[JsonEvent] = Show.show[JsonEvent] { _.showRawJson }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy