1/*
2 * Copyright (C) 2016 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
17package androidx.room.solver
18
19import androidx.room.writer.ClassWriter
20import com.google.common.annotations.VisibleForTesting
21import com.squareup.javapoet.CodeBlock
22
23/**
24 * Defines a code generation scope where we can provide temporary variables, global variables etc
25 */
26class CodeGenScope(val writer: ClassWriter) {
27    private var tmpVarIndices = mutableMapOf<String, Int>()
28    private var builder: CodeBlock.Builder? = null
29    companion object {
30        const val TMP_VAR_DEFAULT_PREFIX = "_tmp"
31        const val CLASS_PROPERTY_PREFIX = "__"
32        @VisibleForTesting
33        fun _tmpVar(index: Int) = _tmpVar(TMP_VAR_DEFAULT_PREFIX, index)
34        fun _tmpVar(prefix: String, index: Int) = "$prefix${if (index == 0) "" else "_$index"}"
35    }
36
37    fun builder(): CodeBlock.Builder {
38        if (builder == null) {
39            builder = CodeBlock.builder()
40        }
41        return builder!!
42    }
43
44    fun getTmpVar(): String {
45        return getTmpVar(TMP_VAR_DEFAULT_PREFIX)
46    }
47
48    fun getTmpVar(prefix: String): String {
49        if (!prefix.startsWith("_")) {
50            throw IllegalArgumentException("tmp variable prefixes should start with _")
51        }
52        if (prefix.startsWith(CLASS_PROPERTY_PREFIX)) {
53            throw IllegalArgumentException("cannot use $CLASS_PROPERTY_PREFIX for tmp variables")
54        }
55        val index = tmpVarIndices.getOrElse(prefix) { 0 }
56        val result = _tmpVar(prefix, index)
57        tmpVarIndices.put(prefix, index + 1)
58        return result
59    }
60
61    fun generate() = builder().build().toString()
62
63    /**
64     * copies all variable indices but excludes generated code.
65     */
66    fun fork(): CodeGenScope {
67        val forked = CodeGenScope(writer)
68        forked.tmpVarIndices.putAll(tmpVarIndices)
69        return forked
70    }
71}
72