12259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar/*
22259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * Copyright (C) 2016 The Android Open Source Project
32259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar *
42259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
52259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * you may not use this file except in compliance with the License.
62259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * You may obtain a copy of the License at
72259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar *
82259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
92259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar *
102259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * Unless required by applicable law or agreed to in writing, software
112259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
122259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * See the License for the specific language governing permissions and
142259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * limitations under the License.
152259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar */
162259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar
17bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viverettepackage androidx.room.solver
182259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar
19bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.writer.ClassWriter
202259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyarimport com.google.common.annotations.VisibleForTesting
212259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyarimport com.squareup.javapoet.CodeBlock
22bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viverette
232259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar/**
242259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * Defines a code generation scope where we can provide temporary variables, global variables etc
252259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar */
266f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikasclass CodeGenScope(val writer: ClassWriter) {
278e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar    private var tmpVarIndices = mutableMapOf<String, Int>()
286f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas    private var builder: CodeBlock.Builder? = null
292259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar    companion object {
308e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar        const val TMP_VAR_DEFAULT_PREFIX = "_tmp"
31645abf12d5a13dae5c2271cedd0563a580871a2bYigit Boyar        const val CLASS_PROPERTY_PREFIX = "__"
322259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar        @VisibleForTesting
336f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas        fun _tmpVar(index: Int) = _tmpVar(TMP_VAR_DEFAULT_PREFIX, index)
346f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas        fun _tmpVar(prefix: String, index: Int) = "$prefix${if (index == 0) "" else "_$index"}"
352259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar    }
362259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar
376f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas    fun builder(): CodeBlock.Builder {
382259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar        if (builder == null) {
392259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar            builder = CodeBlock.builder()
402259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar        }
412259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar        return builder!!
422259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar    }
432259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar
446f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas    fun getTmpVar(): String {
458e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar        return getTmpVar(TMP_VAR_DEFAULT_PREFIX)
468e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar    }
478e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar
486f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas    fun getTmpVar(prefix: String): String {
498e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar        if (!prefix.startsWith("_")) {
50645abf12d5a13dae5c2271cedd0563a580871a2bYigit Boyar            throw IllegalArgumentException("tmp variable prefixes should start with _")
51645abf12d5a13dae5c2271cedd0563a580871a2bYigit Boyar        }
52645abf12d5a13dae5c2271cedd0563a580871a2bYigit Boyar        if (prefix.startsWith(CLASS_PROPERTY_PREFIX)) {
53645abf12d5a13dae5c2271cedd0563a580871a2bYigit Boyar            throw IllegalArgumentException("cannot use $CLASS_PROPERTY_PREFIX for tmp variables")
548e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar        }
558e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar        val index = tmpVarIndices.getOrElse(prefix) { 0 }
568e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar        val result = _tmpVar(prefix, index)
578e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar        tmpVarIndices.put(prefix, index + 1)
588e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar        return result
592259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar    }
602259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar
612259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar    fun generate() = builder().build().toString()
62d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar
63d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar    /**
64d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar     * copies all variable indices but excludes generated code.
65d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar     */
666f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas    fun fork(): CodeGenScope {
67645abf12d5a13dae5c2271cedd0563a580871a2bYigit Boyar        val forked = CodeGenScope(writer)
68d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar        forked.tmpVarIndices.putAll(tmpVarIndices)
69d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar        return forked
70d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar    }
71e2476a0cdc340c8071c938132b2c77b8349c5a01Yigit Boyar}
72