ModelAnalyzer.java revision 3d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43
13d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar/* 23d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * Copyright (C) 2014 The Android Open Source Project 33d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * 43d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 53d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * you may not use this file except in compliance with the License. 63d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * You may obtain a copy of the License at 73d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * 83d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 93d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * 103d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * Unless required by applicable law or agreed to in writing, software 113d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 123d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * See the License for the specific language governing permissions and 143d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar * limitations under the License. 153d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar */ 163d4bdfeeb2ffd1b2ec8a26abd1f4306295a66a43Yigit Boyar 17085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarpackage com.android.databinding.vo 18085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 19085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport com.android.databinding.parser.ExprModel 20085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport kotlin.properties.Delegates 21085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport org.w3c.dom.Node 22085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport com.android.databinding.parser.Expr 23085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport java.util.TreeMap 24085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport com.android.databinding.parser.VariableRef 25085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport com.android.databinding.ext.toCamelCase 26085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport com.android.databinding.ext.joinToCamelCase 27085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport com.android.databinding.ext.extractAndroidId 28085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport com.android.databinding.ext.getAndroidIdPath 29085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport com.android.databinding.util.ClassAnalyzer 30085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport com.android.databinding.util.getMethodOrField 31085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport com.android.databinding.util.Log 32085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport com.android.databinding.ext.joinToCamelCaseAsVar 33085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarimport com.android.databinding.util.isObservable 34085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 35085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar/** 36085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar * Created by yboyar on 11/17/14. 37085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar */ 38085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 39085724fd84795ae1631747443c43f77c08e11a28Yigit Boyarclass Binding(val target : BindingTarget, val targetFieldName : String, val expr : Expr) { 40085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar // which variables effect the result of this binding 41085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar // ordered by depth 42085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val relatedVariables : List<Variable> by Delegates.lazy { 43085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar expr.referencedVariables.map {it.variable} 44085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 45085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 46085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val isDirtyExpr : String by Delegates.lazy { 47085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar relatedVariables.map {it.dirtyFlagName}.join(" | ") 48085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 49085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 50085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val setter = "set${targetFieldName.capitalize()}" 51085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 52085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val isDirtyName by Delegates.lazy {"sDirtyFlag${target.resolvedUniqueName}_${targetFieldName.capitalize()}"} 53085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar} 54085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 55085724fd84795ae1631747443c43f77c08e11a28Yigit Boyardata class BindingTarget(val node: Node, val id: String, val viewClass: String) { 56085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val bindings = arrayListOf<Binding>() 57085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public fun addBinding(fieldName : String, expr : Expr) { 58085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar bindings.add(Binding(this, fieldName, expr)) 59085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 60085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val rId:String by Delegates.lazy { "R.id.$idName" } 61085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val idName by Delegates.lazy { id.extractAndroidId() } 62085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar var resolvedUniqueName : String by Delegates.notNull() 63085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val resolvedViewName by Delegates.lazy{"m${resolvedUniqueName}"} 64085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val idNamePath by Delegates.lazy {node.getAndroidIdPath(false).reverse().map {it.extractAndroidId()}} 65085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val findViewById by Delegates.lazy { 66085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar idNamePath.map {"findViewById(R.id.$it)"}.join(".") 67085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 68085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar} 69085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 70085724fd84795ae1631747443c43f77c08e11a28Yigit Boyardata class Variable(val fullName : String, val parent : Variable? = null) { 71085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar var static : Boolean = false 72085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar var localId : Int by Delegates.notNull() // assigned if and only if variable is non-static observable 73085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val path = fullName.split("\\.") 74085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val name = path.last() 75085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar var uniqueName = fullName // TODO change if we support variables w/ the same name 76085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar var klassName : String by Delegates.notNull() 77085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val children = arrayListOf<Variable>() 78085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val observableChildren by Delegates.lazy {children.filter{it.isObservable}} 79085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val descendents : List<Variable> by Delegates.lazy {children + children.flatMap{it.descendents}} 80085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val observableDescendents : List<Variable> by Delegates.lazy {descendents.filter{it.isObservable}} 81085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar var isRootVariable = false 82085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val defaultValue by Delegates.lazy { ClassAnalyzer.instance.getDefaultValue(klassName)} 83085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val resolvedClass : Class<*> by Delegates.lazy { 84085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar ClassAnalyzer.instance.loadClass(klassName) 85085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 86085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val getter : String by Delegates.lazy { 87085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (parent == null) { 88085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar name 89085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } else { 90085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val pair = parent.resolvedClass.getMethodOrField(name) 91085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar klassName = pair.second 92085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar pair.first 93085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 94085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 95085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val fullCamelCase = uniqueName.split("\\.").joinToCamelCase() 96085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar // has to be lazy to get up to date static value 97085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar // TODO handle final pbulic instead! 98085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val localName by Delegates.lazy {if (static) getterGlobal else "${uniqueName.split("\\.").joinToCamelCaseAsVar()}" } 99085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val localIdName by Delegates.lazy { if(localId > -1) "s$fullCamelCase" else "<ERROR>" }//just adding a reference to localId to detect errors 100085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val dirtyFlag : Int by Delegates.lazy { (Math.pow(2.toDouble(), localId.toDouble())).toInt() } 101085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val dirtyFlagName by Delegates.lazy {if (static) "0" else "flag$fullCamelCase"} 102085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val variablePath : List<Variable> by Delegates.lazy { 103085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (parent == null) arrayListOf(this) else parent.variablePath + arrayListOf(this) 104085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 105085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val isDirtyExpr : String by Delegates.lazy { 106085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar variablePath.map {it.dirtyFlagName}.join(" | ") 107085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 108085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 109085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val childrenDirtyFlagsExpr: String by Delegates.lazy { 110085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar (children.map{it.childrenDirtyFlagsExpr } + arrayListOf(dirtyFlagName)).join(" | ") 111085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 112085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 113085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val isDirtyName : String = "isDirty$fullCamelCase" 114085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 115085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val childrenDirtyFlagName: String = "flagHasDirtyChild$fullCamelCase" 116085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 117085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val onChange : String by Delegates.lazy { "onChange$fullCamelCase"} 118085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 119085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val declare : String by Delegates.lazy { "$klassName $name" } 120085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 121085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val declareLocal : String by Delegates.lazy { "$klassName $localName" } 122085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 123085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val isObservable : Boolean by Delegates.lazy { 124085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar resolvedClass.isObservable() 125085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 126085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 127085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val isPrimitive : Boolean by Delegates.lazy {resolvedClass.isPrimitive()} 128085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 129085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val setter by Delegates.lazy {"set$fullCamelCase"} 130085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 131085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val getterGlobal : String by Delegates.lazy { 132085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (parent == null) { 133085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (static) { 134085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar klassName 135085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } else { 136085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar "this.$name" 137085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 138085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } else { 139085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar "${parent.getterGlobal}.$getter" 140085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 141085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 142085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 143085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val getterOnParentLocal by Delegates.lazy { 144085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (parent == null) { 145085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (static) { 146085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar klassName 147085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } else { 148085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar "this.$name" 149085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 150085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } else { 151085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar "${parent.localName}.$getter" 152085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 153085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 154085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 155085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar fun markAsStatic() { 156085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar static = true 157085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar children.forEach{it.markAsStatic()} 158085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 159085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar} 160085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 161085724fd84795ae1631747443c43f77c08e11a28Yigit Boyaropen data class VariableDefinition(val name : String, val klass : String, val static : Boolean = false) 162085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 163085724fd84795ae1631747443c43f77c08e11a28Yigit Boyardata class VariableScope(val node : Node, val variables : MutableList<VariableDefinition> = arrayListOf()) 164085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 165085724fd84795ae1631747443c43f77c08e11a28Yigit Boyardata class StaticClass(name : String, klass : String) : VariableDefinition(name, klass, true) 166085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 167085724fd84795ae1631747443c43f77c08e11a28Yigit Boyardata class LayoutExprBinding(val root : Node) { 168085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar var exprModel : ExprModel by Delegates.notNull() 169085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val variableScopes = hashMapOf<Node, VariableScope>() 170085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val bindingTargets = arrayListOf<BindingTarget>() 171085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val variables = TreeMap<String, Variable>() 172085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val rootVariables = hashMapOf<String, Variable>() 173085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val dynamicVariables : List<Variable> by Delegates.lazy {variables.values().filterNot{it.static}} 174085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val observableVariables by Delegates.lazy {dynamicVariables.filter{it.isObservable}} 175085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val bindings by Delegates.lazy { 176085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar bindingTargets.flatMap{it.bindings} 177085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 178085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 179085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val staticVariableScope : VariableScope by Delegates.lazy { 180085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar var existing = variableScopes[root] 181085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (existing == null) { 182085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar existing = VariableScope(root) 183085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar variableScopes.put(root, existing) 184085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 185085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar existing!! 186085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 187085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 188085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public fun addVariableScope(scope : VariableScope) { 189085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (variableScopes.put(scope.node, scope) != null) { 190085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar throw IllegalArgumentException("duplicate scope created for node ${scope.node}") 191085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 192085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 193085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 194085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public fun addStaticClass(name : String, klass : String) { 195085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar staticVariableScope.variables.add(VariableDefinition(name, klass, true)) 196085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 197085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 198085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar private fun toVariable(ref : VariableRef, klassLookup : Map<String, String>) : Variable { 199085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar var existing = variables[ref.fullName] 200085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (existing != null) { 201085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return existing 202085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 203085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar var parent = if (ref.parent == null) null else toVariable(ref.parent, klassLookup) 204085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar existing = Variable(ref.fullName, parent) 205085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (parent == null) { 206085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar existing.klassName = klassLookup[existing.fullName]!! 207085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar rootVariables[ref.fullName] = existing 208085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar existing.isRootVariable = true 209085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } else { 210085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar parent!!.children.add(existing) 211085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 212085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 213085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar variables[ref.fullName] = existing 214085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar ref.variable = existing 215085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar return existing 216085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 217085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 218085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar fun pack() { 219085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar exprModel.pack() //seal the model, nothing will be added after this 220085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 221085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar // assign klass to root variables that we can 222085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val rootVariableKlasses = TreeMap<String, String>() 223085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar val staticVariableKlasses = TreeMap<String, String>() 224085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar variableScopes.forEach { 225085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar it.value.variables.forEach { 226085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (rootVariableKlasses.put(it.name, it.klass) != null) { 227085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar throw IllegalArgumentException("two variables cannot share the same name yet") 228085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 229085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (it.static) { 230085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar staticVariableKlasses.put(it.name, it.klass) 231085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 232085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 233085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 234085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 235085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar // convert variable references to variables 236085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar exprModel.variables.forEach { entry -> 237085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar Log.d("converting ${entry.value} to variable") 238085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar toVariable(entry.value, rootVariableKlasses) 239085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 240085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 241085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar rootVariables.values().forEach { 242085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (staticVariableKlasses.contains(it.name)) { 243085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar it.markAsStatic() 244085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 245085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 246085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 247085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar // assign unique names to views 248085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar bindingTargets.groupBy{ it.idName }.forEach { 249085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar if (it.value.size() == 1) { 250085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar it.value[0].resolvedUniqueName = "${it.value[0].idName.toCamelCase()}" 251085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } else { 252085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar it.value.forEach { 253085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar it.resolvedUniqueName = "${it.idNamePath.joinToCamelCase()}" 254085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 255085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 256085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 257085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 258085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 259085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar public fun analyzeVariables() { 260085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar variables.forEach { 261085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar Log.d("resolving method for ${it.key}") 262085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar it.value.getter 263085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar Log.d("resolved method / field for ${it.key} is ${it.value.getter} of type ${it.value.klassName}") 264085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 265085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar 266085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar // set ids on observables first then in other variables 267085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar // observable ids are used for observer references which is why they get first ids 268085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar var id = 0 269085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar observableVariables.forEach { it.localId = id++ } 270085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar dynamicVariables.filterNot { it.isObservable }.forEach { it.localId = id++ } 271085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar } 272085724fd84795ae1631747443c43f77c08e11a28Yigit Boyar}