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

commonMain.at.asitplus.jsonpath.implementation.AntlrJsonPathCompiler.kt Maven / Gradle / Ivy

package at.asitplus.jsonpath.implementation

import at.asitplus.jsonpath.core.JsonPathCompiler
import at.asitplus.jsonpath.core.JsonPathFunctionExtension
import at.asitplus.jsonpath.core.JsonPathQuery
import at.asitplus.jsonpath.core.NodeList
import at.asitplus.jsonpath.generated.JsonPathLexer
import at.asitplus.jsonpath.generated.JsonPathParser
import kotlinx.serialization.json.JsonElement
import org.antlr.v4.kotlinruntime.CharStreams
import org.antlr.v4.kotlinruntime.CommonTokenStream
import org.antlr.v4.kotlinruntime.ListTokenSource

class AntlrJsonPathCompiler(
    private var errorListener: AntlrJsonPathCompilerErrorListener? = null,
) : JsonPathCompiler {
    override fun compile(
        jsonPath: String,
        functionExtensionRetriever: (String) -> JsonPathFunctionExtension<*>?,
    ): JsonPathQuery {
        val lexerErrorDetector = AntlrSyntaxErrorDetector()
        val tokens = JsonPathLexer(CharStreams.fromString(jsonPath)).apply {
            addErrorListener(lexerErrorDetector)
            errorListener?.let {
                addErrorListener(it)
            }
        }.allTokens

        if (lexerErrorDetector.isError) {
            throw JsonPathLexerException()
        }

        val parserErrorDetector = AntlrSyntaxErrorDetector()
        val commonTokenStream = CommonTokenStream(ListTokenSource(tokens))
        val jsonPathQueryContext = JsonPathParser(commonTokenStream).apply {
            addErrorListener(parserErrorDetector)
            errorListener?.let {
                addErrorListener(it)
            }
        }.jsonpath_query()

        if (parserErrorDetector.isError) {
            throw JsonPathParserException()
        }

        val abstractSyntaxTree = AntlrJsonPathSemanticAnalyzerVisitor(
            errorListener = errorListener,
            functionExtensionRetriever = functionExtensionRetriever,
        ).visit(jsonPathQueryContext)
        val rootValueType = abstractSyntaxTree?.value

        if (rootValueType is JsonPathExpression.ErrorType) {
            throw JsonPathTypeCheckerException("Type errors have occured: $abstractSyntaxTree")
        }
        if (rootValueType !is JsonPathExpression.FilterExpression.NodesExpression.FilterQueryExpression) {
            throw JsonPathTypeCheckerException("Invalid root value type: $rootValueType: $abstractSyntaxTree")
        }

        return object : JsonPathQuery {
            override fun invoke(currentNode: JsonElement, rootNode: JsonElement): NodeList {
                return rootValueType.jsonPathQuery.invoke(
                    currentNode = currentNode,
                    rootNode = rootNode,
                )
            }
        }
    }

    fun setErrorListener(errorListener: AntlrJsonPathCompilerErrorListener?) {
        this.errorListener = errorListener
    }

    fun getErrorListener(): AntlrJsonPathCompilerErrorListener? {
        return errorListener
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy