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

commonMain.jetbrains.datalore.base.json.JsonParser.kt Maven / Gradle / Ivy

There is a newer version: 4.5.3-alpha1
Show newest version
/*
 * Copyright (c) 2020. JetBrains s.r.o.
 * Use of this source code is governed by the MIT license that can be found in the LICENSE file.
 */

package jetbrains.datalore.base.json

class JsonParser(
    private val json: String
) {
    fun parseJson(): Any? {
        val lexer = JsonLexer(json)
        return parseValue(lexer)
    }

    private fun parseValue(lexer: JsonLexer): Any? {
        return when(lexer.currentToken) {
            Token.STRING -> lexer.tokenValue().unescape().also { lexer.nextToken() }
            Token.NUMBER -> lexer.tokenValue().toDouble().also { lexer.nextToken() }
            Token.FALSE -> false.also { lexer.nextToken() }
            Token.TRUE -> true.also { lexer.nextToken() }
            Token.NULL -> null.also { lexer.nextToken() }
            Token.LEFT_BRACE -> parseObject(lexer)
            Token.LEFT_BRACKET -> parseArray(lexer)
            else -> error("Invalid token: ${lexer.currentToken}")
        }
    }

    private fun parseArray(lexer: JsonLexer): MutableList {
        fun checkCurrentToken(token: Token) { require(lexer.currentToken, token, "[Arr] ") }

        val list = mutableListOf()

        checkCurrentToken(Token.LEFT_BRACKET)
        lexer.nextToken()

        while (lexer.currentToken != Token.RIGHT_BRACKET) {
            if (list.isNotEmpty()) {
                checkCurrentToken(Token.COMMA)
                lexer.nextToken()
            }
            list.add(parseValue(lexer))
        }

        checkCurrentToken(Token.RIGHT_BRACKET)
        lexer.nextToken()

        return list
    }

    private fun parseObject(lexer: JsonLexer): Map {
        fun checkCurrentToken(token: Token) { require(lexer.currentToken, token, "[Obj] ") }

        val map = mutableMapOf()

        checkCurrentToken(Token.LEFT_BRACE)
        lexer.nextToken()

        while (lexer.currentToken != Token.RIGHT_BRACE) {
            if (map.isNotEmpty()) {
                checkCurrentToken(Token.COMMA)
                lexer.nextToken()
            }

            checkCurrentToken(Token.STRING)
            val key = lexer.tokenValue().unescape()
            lexer.nextToken()

            checkCurrentToken(Token.COLON)
            lexer.nextToken()

            val value = parseValue(lexer)
            map[key] = value
        }

        checkCurrentToken(Token.RIGHT_BRACE)
        lexer.nextToken()

        return map
    }

    private fun require(current: Token?, expected: Token?, messagePrefix: String? = null) {
        if (current != expected) {
            throw JsonException(messagePrefix + "Expected token: $expected, actual: $current")
        }
    }

    class JsonException(message: String) : Exception(message)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy