1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.room.parser
18 
19 import org.antlr.v4.runtime.BaseErrorListener
20 import org.antlr.v4.runtime.CharStreams
21 import org.antlr.v4.runtime.CommonTokenStream
22 import org.antlr.v4.runtime.RecognitionException
23 import org.antlr.v4.runtime.Recognizer
24 
25 /** Helper class to parse a single statement out of a query. */
26 object SingleQuerySqlParser {
parsenull27     fun <T> parse(
28         input: String,
29         visit: (statement: SQLiteParser.Sql_stmtContext, syntaxErrors: MutableList<String>) -> T,
30         fallback: (syntaxErrors: List<String>) -> T
31     ): T {
32         val inputStream = CharStreams.fromString(input)
33         val lexer = SQLiteLexer(inputStream)
34         val tokenStream = CommonTokenStream(lexer)
35         val parser = SQLiteParser(tokenStream)
36         val syntaxErrors = arrayListOf<String>()
37         parser.addErrorListener(
38             object : BaseErrorListener() {
39                 override fun syntaxError(
40                     recognizer: Recognizer<*, *>,
41                     offendingSymbol: Any,
42                     line: Int,
43                     charPositionInLine: Int,
44                     msg: String,
45                     e: RecognitionException?
46                 ) {
47                     syntaxErrors.add(msg)
48                 }
49             }
50         )
51         try {
52             val parsed = parser.parse()
53             val statementList = parsed.sql_stmt_list()
54             if (statementList.isEmpty()) {
55                 return fallback(listOf(ParserErrors.NOT_ONE_QUERY))
56             }
57             val statements =
58                 statementList.first().children.filterIsInstance<SQLiteParser.Sql_stmtContext>()
59             if (statements.size != 1) {
60                 syntaxErrors.add(ParserErrors.NOT_ONE_QUERY)
61             }
62             val statement = statements.first()
63             return visit(statement, syntaxErrors)
64         } catch (antlrError: RuntimeException) {
65             syntaxErrors.add("unknown error while parsing $input : ${antlrError.message}")
66             return fallback(syntaxErrors)
67         }
68     }
69 }
70