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

implementations.StandardParser.kt Maven / Gradle / Ivy

The newest version!
package com.github.fluidsonic.fluid.json


internal object StandardParser : JSONParser {

	private fun parse(source: JSONReader, expectedType: ExpectedType, withTermination: Boolean) =
		source.withTermination(withTermination) { parseUnterminated(source, expectedType) }


	override fun parseValueOrNull(source: JSONReader, withTermination: Boolean) =
		parse(source, ExpectedType.any, withTermination = withTermination)


	override fun parseList(source: JSONReader, withTermination: Boolean) =
		parse(source, ExpectedType.list, withTermination = withTermination) as List<*>


	@Suppress("UNCHECKED_CAST")
	override fun parseMap(source: JSONReader, withTermination: Boolean) =
		parse(source, ExpectedType.map, withTermination = withTermination) as Map


	@Suppress("UNCHECKED_CAST")
	private fun parseUnterminated(source: JSONReader, expectedType: ExpectedType): Any? {
		var currentList: MutableList? = null
		var currentKey: String? = null
		var currentMap: MutableMap? = null
		val parents = mutableListOf()
		val parentKeys = mutableListOf()

		when (expectedType) {
			ExpectedType.any -> Unit

			ExpectedType.list -> source.nextToken == JSONToken.listStart ||
				throw JSONException.Schema(
					message = "Expected a list, got ${source.nextToken}",
					offset = source.offset,
					path = source.path
				)

			ExpectedType.map -> source.nextToken == JSONToken.mapStart ||
				throw JSONException.Schema(
					message = "Expected a map, got ${source.nextToken}",
					offset = source.offset,
					path = source.path
				)
		}

		loop@ while (true) {
			val value: Any? = when (source.nextToken) {
				JSONToken.booleanValue ->
					source.readBoolean()

				JSONToken.listEnd -> {
					source.readListEnd()

					val list = currentList

					val parentCount = parents.size
					if (parentCount > 0) {
						val parent = parents.removeAt(parentCount - 1)
						if (parent is MutableList<*>) {
							currentList = parent as MutableList
						}
						else {
							currentList = null
							currentMap = parent as MutableMap
						}
					}
					else {
						currentList = null
						currentMap = null
					}

					list
				}

				JSONToken.listStart -> {
					source.readListStart()

					val list = mutableListOf()
					if (currentList != null) {
						parents += currentList
					}
					else if (currentMap != null) {
						parents += currentMap
						currentMap = null
					}

					currentList = list
					continue@loop
				}

				JSONToken.nullValue
				-> source.readNull()

				JSONToken.mapEnd -> {
					source.readMapEnd()

					val map = currentMap

					val parentCount = parents.size
					if (parentCount > 0) {
						val parent = parents.removeAt(parentCount - 1)
						if (parent is MutableMap<*, *>) {
							currentMap = parent as MutableMap
						}
						else {
							currentList = parent as MutableList
							currentMap = null
						}
					}
					else {
						currentList = null
						currentMap = null
					}

					val parentKeyCount = parentKeys.size
					if (parentKeyCount > 0) {
						currentKey = parentKeys.removeAt(parentKeyCount - 1)
					}

					map
				}

				JSONToken.mapKey -> {
					currentKey = source.readMapKey()
					continue@loop
				}

				JSONToken.mapStart -> {
					source.readMapStart()

					val map = mutableMapOf()
					if (currentMap != null) {
						parents += currentMap
					}
					else if (currentList != null) {
						parents += currentList
						currentList = null
					}

					if (currentKey != null) {
						parentKeys += currentKey
						currentKey = null
					}

					currentMap = map
					continue@loop
				}

				JSONToken.numberValue ->
					source.readNumber()

				JSONToken.stringValue ->
					source.readString()

				else ->
					throw IllegalStateException("reader is messed up: ${source.nextToken}")
			}

			when {
				currentList != null -> currentList.add(value)
				currentMap != null -> currentMap[currentKey] = value
				else -> return value
			}
		}
	}


	private enum class ExpectedType {
		any, list, map
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy