SingleQuerySqlParser.kt
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.room.parser
import org.antlr.v4.runtime.BaseErrorListener
import org.antlr.v4.runtime.CharStreams
import org.antlr.v4.runtime.CommonTokenStream
import org.antlr.v4.runtime.RecognitionException
import org.antlr.v4.runtime.Recognizer
/**
* Helper class to parse a single statement out of a query.
*/
object SingleQuerySqlParser {
fun <T> parse(
input: String,
visit: (statement: SQLiteParser.Sql_stmtContext, syntaxErrors: MutableList<String>) -> T,
fallback: (syntaxErrors: List<String>) -> T
): T {
val inputStream = CharStreams.fromString(input)
val lexer = SQLiteLexer(inputStream)
val tokenStream = CommonTokenStream(lexer)
val parser = SQLiteParser(tokenStream)
val syntaxErrors = arrayListOf<String>()
parser.addErrorListener(object : BaseErrorListener() {
override fun syntaxError(
recognizer: Recognizer<*, *>,
offendingSymbol: Any,
line: Int,
charPositionInLine: Int,
msg: String,
e: RecognitionException?
) {
syntaxErrors.add(msg)
}
})
try {
val parsed = parser.parse()
val statementList = parsed.sql_stmt_list()
if (statementList.isEmpty()) {
return fallback(listOf(ParserErrors.NOT_ONE_QUERY))
}
val statements = statementList.first().children
.filterIsInstance<SQLiteParser.Sql_stmtContext>()
if (statements.size != 1) {
syntaxErrors.add(ParserErrors.NOT_ONE_QUERY)
}
val statement = statements.first()
return visit(statement, syntaxErrors)
} catch (antlrError: RuntimeException) {
syntaxErrors.add("unknown error while parsing $input : ${antlrError.message}")
return fallback(syntaxErrors)
}
}
}