From 32a8409ae8da818e8559dac0e42d6da083c1e195 Mon Sep 17 00:00:00 2001 From: Yigit Boyar Date: Thu, 11 Dec 2014 15:23:36 -0800 Subject: initial commit --- tools/data-binding/build.gradle | 13 + tools/data-binding/compiler/build.gradle | 32 + .../java/com/example/databinding/LayoutParser.java | 45 ++ .../kotlin/com/android/databinding/ext/list_ext.kt | 61 ++ .../kotlin/com/android/databinding/ext/node_ext.kt | 25 + .../com/android/databinding/ext/string_ext.kt | 39 + .../main/kotlin/com/android/databinding/main.kt | 254 +++++++ .../databinding/parser/expression_parser.kt | 110 +++ .../com/android/databinding/parser/expressions.kt | 98 +++ .../android/databinding/renderer/attr_renderer.kt | 29 + .../databinding/renderer/binding_br_renderer.kt | 37 + .../databinding/renderer/data_binder_renderer.kt | 32 + .../renderer/view_expr_binder_renderer.kt | 181 +++++ .../kotlin/com/android/databinding/util/Log.kt | 7 + .../com/android/databinding/util/class_analyzer.kt | 117 +++ .../main/kotlin/com/android/databinding/vo/vo.kt | 256 +++++++ .../com.android.databinding.properties | 1 + tools/data-binding/gradle.properties | 3 + .../data-binding/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 51017 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + tools/data-binding/gradlePlugin/build.gradle | 35 + .../gradlePlugin/src/main/kotlin/plugin.kt | 231 ++++++ tools/data-binding/gradlew | 164 ++++ tools/data-binding/grammerBuilder/DataBinder.g4 | 104 +++ tools/data-binding/grammerBuilder/build.gradle | 49 ++ .../com/android/databinding/DataBinder.tokens | 31 + .../databinding/DataBinderBaseListener.java | 261 +++++++ .../android/databinding/DataBinderBaseVisitor.java | 151 ++++ .../com/android/databinding/DataBinderLexer.java | 130 ++++ .../com/android/databinding/DataBinderLexer.tokens | 31 + .../android/databinding/DataBinderListener.java | 218 ++++++ .../com/android/databinding/DataBinderParser.java | 829 +++++++++++++++++++++ .../com/android/databinding/DataBinderVisitor.java | 143 ++++ .../java/com/android/databinder/parser/Main.java | 24 + tools/data-binding/library/build.gradle | 69 ++ .../library/src/main/AndroidManifest.xml | 4 + .../databinding/library/BaseObservable.java | 32 + .../android/databinding/library/DataBinder.java | 106 +++ .../databinding/library/DataBinderMapper.java | 11 + .../databinding/library/IViewDataBinder.java | 11 + .../android/databinding/library/Observable.java | 9 + .../databinding/library/ObservableHelper.java | 53 ++ .../databinding/library/ObservableListener.java | 9 + .../databinding/library/ViewDataBinder.java | 155 ++++ tools/data-binding/settings.gradle | 9 + 45 files changed, 4215 insertions(+) create mode 100644 tools/data-binding/build.gradle create mode 100644 tools/data-binding/compiler/build.gradle create mode 100644 tools/data-binding/compiler/src/main/java/com/example/databinding/LayoutParser.java create mode 100644 tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/list_ext.kt create mode 100644 tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/node_ext.kt create mode 100644 tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/string_ext.kt create mode 100644 tools/data-binding/compiler/src/main/kotlin/com/android/databinding/main.kt create mode 100644 tools/data-binding/compiler/src/main/kotlin/com/android/databinding/parser/expression_parser.kt create mode 100644 tools/data-binding/compiler/src/main/kotlin/com/android/databinding/parser/expressions.kt create mode 100644 tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/attr_renderer.kt create mode 100644 tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/binding_br_renderer.kt create mode 100644 tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/data_binder_renderer.kt create mode 100644 tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/view_expr_binder_renderer.kt create mode 100644 tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/Log.kt create mode 100644 tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/class_analyzer.kt create mode 100644 tools/data-binding/compiler/src/main/kotlin/com/android/databinding/vo/vo.kt create mode 100644 tools/data-binding/compiler/src/main/resources/META-INF/gradle-plugins/com.android.databinding.properties create mode 100644 tools/data-binding/gradle.properties create mode 100644 tools/data-binding/gradle/wrapper/gradle-wrapper.jar create mode 100644 tools/data-binding/gradle/wrapper/gradle-wrapper.properties create mode 100644 tools/data-binding/gradlePlugin/build.gradle create mode 100644 tools/data-binding/gradlePlugin/src/main/kotlin/plugin.kt create mode 100755 tools/data-binding/gradlew create mode 100644 tools/data-binding/grammerBuilder/DataBinder.g4 create mode 100644 tools/data-binding/grammerBuilder/build.gradle create mode 100644 tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinder.tokens create mode 100644 tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderBaseListener.java create mode 100644 tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderBaseVisitor.java create mode 100644 tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderLexer.java create mode 100644 tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderLexer.tokens create mode 100644 tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderListener.java create mode 100644 tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderParser.java create mode 100644 tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderVisitor.java create mode 100644 tools/data-binding/grammerBuilder/src/main/java/com/android/databinder/parser/Main.java create mode 100644 tools/data-binding/library/build.gradle create mode 100644 tools/data-binding/library/src/main/AndroidManifest.xml create mode 100644 tools/data-binding/library/src/main/java/com/android/databinding/library/BaseObservable.java create mode 100644 tools/data-binding/library/src/main/java/com/android/databinding/library/DataBinder.java create mode 100644 tools/data-binding/library/src/main/java/com/android/databinding/library/DataBinderMapper.java create mode 100644 tools/data-binding/library/src/main/java/com/android/databinding/library/IViewDataBinder.java create mode 100644 tools/data-binding/library/src/main/java/com/android/databinding/library/Observable.java create mode 100644 tools/data-binding/library/src/main/java/com/android/databinding/library/ObservableHelper.java create mode 100644 tools/data-binding/library/src/main/java/com/android/databinding/library/ObservableListener.java create mode 100644 tools/data-binding/library/src/main/java/com/android/databinding/library/ViewDataBinder.java create mode 100644 tools/data-binding/settings.gradle (limited to 'tools') diff --git a/tools/data-binding/build.gradle b/tools/data-binding/build.gradle new file mode 100644 index 0000000..a672313 --- /dev/null +++ b/tools/data-binding/build.gradle @@ -0,0 +1,13 @@ +apply plugin: 'java' + +sourceCompatibility = 1.7 + +version = '1.0' + +repositories { + mavenCentral() +} + +dependencies { + testCompile group: 'junit', name: 'junit', version: '4.11' +} \ No newline at end of file diff --git a/tools/data-binding/compiler/build.gradle b/tools/data-binding/compiler/build.gradle new file mode 100644 index 0000000..eb1796f --- /dev/null +++ b/tools/data-binding/compiler/build.gradle @@ -0,0 +1,32 @@ +apply plugin: 'java' +apply plugin: "kotlin" +apply plugin: 'maven' +buildscript { + repositories { + mavenLocal() + mavenCentral() + } + dependencies { + classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:0.9.206' + } +} + +repositories { + mavenCentral() + mavenLocal() +} + +dependencies { + compile 'org.jetbrains.kotlin:kotlin-stdlib:0.9.206' + compile 'com.android.databinding:grammerBuilder:0.1-SNAPSHOT' +} +uploadArchives { + repositories { + mavenDeployer { + repository(url: mavenLocal().url) + pom.version = '0.2-SNAPSHOT' + pom.artifactId = 'compiler' + pom.groupId='com.android.databinding' + } + } +} \ No newline at end of file diff --git a/tools/data-binding/compiler/src/main/java/com/example/databinding/LayoutParser.java b/tools/data-binding/compiler/src/main/java/com/example/databinding/LayoutParser.java new file mode 100644 index 0000000..0b20765 --- /dev/null +++ b/tools/data-binding/compiler/src/main/java/com/example/databinding/LayoutParser.java @@ -0,0 +1,45 @@ +package com.example.databinding; + +import com.android.databinding.util.ClassAnalyzer; +import com.android.databinding.KLayoutParser; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class LayoutParser { + public static void main(String[] args) throws MalformedURLException { + KLayoutParser parser = new KLayoutParser("com.android.bindingapp", + Arrays.asList(new File("/Users/yboyar/Documents/git/BindingApp/app/src/main/res")), + new File("/Users/yboyar/Documents/git/BindingApp/app/build/generated/source/r/debug"), + new File("/Users/yboyar/Documents/git/BindingApp/app/build/intermediates/res/debug")); + parser.process(); + parser.writeAttrFile(); + parser.writeBrFile(); + + URL jarUrl = new File("/Users/yboyar/android/sdk/platforms/android-21/android.jar").toURI().toURL(); + URLClassLoader androidClassLoader = new URLClassLoader(new URL[]{jarUrl}); + List cpFiles = new ArrayList<>(); + cpFiles.add(new File("/Users/yboyar/Documents/git/BindingApp/app/build/intermediates/classes/debug")); + cpFiles.add(new File("/Users/yboyar/Documents/git/BindingApp/app/build/intermediates/dependency-cache/debug")); + cpFiles.add(new File( + "/Users/yboyar/Documents/git/BindingApp/app/build/intermediates/exploded-aar/com.android.databinding/library/0.1-SNAPSHOT/classes.jar")); + cpFiles.add(new File( + "/Users/yboyar/Documents/git/BindingApp/app/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/21.0.0/classes.jar" + )); + URL[] urls = new URL[cpFiles.size()]; + for (int i = 0; i < cpFiles.size(); i++) { + urls[i] = cpFiles.get(i).toURI().toURL(); + } + URLClassLoader classLoader = new URLClassLoader(urls, androidClassLoader); + parser.writeViewBinderInterfaces(); + parser.setClassAnalyzer(new ClassAnalyzer(classLoader)); + parser.analyzeClasses(); + parser.writeDbrFile(); + parser.writeViewBinders(); + } +} diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/list_ext.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/list_ext.kt new file mode 100644 index 0000000..087dec2 --- /dev/null +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/list_ext.kt @@ -0,0 +1,61 @@ +package com.android.databinding.ext + +import com.android.databinding.ext.toCamelCase +import com.android.databinding.ext.toCamelCaseAsVar +import com.android.databinding.ext.times +import com.android.databinding.ext.getIndentation + +/** + * Created by yboyar on 11/11/14. + */ +public fun List.joinToCamelCase(): String = when(size()) { + 0 -> throw IllegalArgumentException("invalid section size, cannot be zero") + 1 -> this.get(0).toCamelCase() + else -> this.map {it.toCamelCase()}.joinToString("") +} + +public fun List.joinToCamelCaseAsVar(): String = when(size()) { + 0 -> throw IllegalArgumentException("invalid section size, cannot be zero") + 1 -> this.get(0).toCamelCaseAsVar() + else -> get(0).toCamelCaseAsVar() + drop(1).joinToCamelCase() +} + +public fun Array.joinToCamelCase(): String = when(size) { + 0 -> throw IllegalArgumentException("invalid section size, cannot be zero") + 1 -> this.get(0).toCamelCase() + else -> this.map {it.toCamelCase()}.joinToString("") +} + +public fun Array.joinToCamelCaseAsVar(): String = when(size) { + 0 -> throw IllegalArgumentException("invalid section size, cannot be zero") + 1 -> this.get(0).toCamelCaseAsVar() + else -> get(0).toCamelCaseAsVar() + drop(1).joinToCamelCase() +} + +public fun List.joinIndented(indentation : Int) : String { + val sb = StringBuilder() + val indent = " ".times(indentation) + for (line in this) { + if (line.trim() == "") continue; + sb.append(indent).append(line).append("\n") + } + return sb.toString() +} + +public fun List.joinIndentedExceptFirst(indentation : Int) : String { + if (size == 0) return "" + if (size == 1) return this.get(0) + val sb = StringBuilder() + val indent = " ".times(indentation) + sb.append(this.get(0)) + for (i in 1..size - 1) { + if (this[i].trim() == "") continue; + sb.append("\n").append(indent).append(this.get(i)) + } + return sb.toString() +} + +public fun List.joinIndented() : String { + if (size < 2) return this.get(0) + return this.get(0) + "\n" + drop(1).joinIndented(this.get(0).getIndentation()) +} \ No newline at end of file diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/node_ext.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/node_ext.kt new file mode 100644 index 0000000..c52bec7 --- /dev/null +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/node_ext.kt @@ -0,0 +1,25 @@ +package com.android.databinding.ext + +import org.w3c.dom.Node + +/** + * Created by yboyar on 11/11/14. + */ + +public fun Node.getAndroidId() : String? = + getAttributes()?.getNamedItem("android:id")?.getNodeValue() + +public fun Node.getAndroidIdPath(includeRoot : Boolean) : List { + val ids = arrayListOf() + ids.add(getAndroidId()!!) + var parent : Node? = getParentNode() + while (parent != null && (includeRoot || parent?.getParentNode()?.getParentNode() != null)) { + val id = parent?.getAndroidId() + if (id != null) { + ids.add(id) + } + parent = parent?.getParentNode() + } + return ids +} + diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/string_ext.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/string_ext.kt new file mode 100644 index 0000000..e12b964 --- /dev/null +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/ext/string_ext.kt @@ -0,0 +1,39 @@ +package com.android.databinding.ext + +import com.android.databinding.ext.joinToCamelCase +import com.android.databinding.ext.joinToCamelCaseAsVar +import com.android.databinding.ext.joinIndented +import com.android.databinding.ext.joinIndentedExceptFirst + +/** + * Created by yboyar on 11/11/14. + */ +public fun String.extractAndroidId() : String = this.split("/")[1] + +public fun String.times(x : Int) : String = 0.rangeTo(x-1).map { this }.join("") + +public fun String.indent(x : Int) : String = split("\n").filterNot{it.trim() == ""}.joinIndented(x) + +public fun String.indentExceptFirst(x : Int) : String = split("\n").filterNot{it.trim() == ""}.joinIndentedExceptFirst(x) + +public fun String.getIndentation() : Int { + var count = 0 + while ((count < this.length) && (this[count] <= ' ')) { + count++ + } + return count +} + +public fun String.toCamelCase() : String { + val split = this.split("_") + if (split.size == 0) return "" + if (split.size == 1) return split[0].capitalize() + return split.joinToCamelCase() +} + +public fun String.toCamelCaseAsVar() : String { + val split = this.split("_") + if (split.size == 0) return "" + if (split.size == 1) return split[0] + return split.joinToCamelCaseAsVar() +} \ No newline at end of file diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/main.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/main.kt new file mode 100644 index 0000000..e22824e --- /dev/null +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/main.kt @@ -0,0 +1,254 @@ +package com.android.databinding + +import org.w3c.dom.Document +import org.w3c.dom.NamedNodeMap +import org.w3c.dom.Node +import org.w3c.dom.NodeList +import org.xml.sax.SAXException + +import java.io.File +import java.io.FilenameFilter +import java.io.IOException +import java.util.ArrayList + +import javax.xml.parsers.DocumentBuilder +import javax.xml.parsers.DocumentBuilderFactory +import javax.xml.parsers.ParserConfigurationException +import javax.xml.xpath.XPath +import javax.xml.xpath.XPathConstants +import javax.xml.xpath.XPathExpression +import javax.xml.xpath.XPathExpressionException +import javax.xml.xpath.XPathFactory +import kotlin.properties.Delegates +import java.util.HashMap + +import com.android.databinding.parser.ExpressionParser +import com.android.databinding.renderer.BrRenderer +import com.android.databinding.renderer.DataBinderRenderer +import com.android.databinding.renderer.AttrRenderer +import com.android.databinding.renderer.ViewExprBinderRenderer +import com.android.databinding.util.ClassAnalyzer +import com.android.databinding.vo.LayoutExprBinding +import com.android.databinding.vo.VariableScope +import com.android.databinding.vo.VariableDefinition +import com.android.databinding.vo.BindingTarget + + + +public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Iterable, + val outputBaseDir : File, val outputResBaseDir : File) { + var br : BrRenderer by Delegates.notNull() + var dbr : DataBinderRenderer by Delegates.notNull() + var styler : AttrRenderer by Delegates.notNull() + val viewExprBinderRenderers = arrayListOf() + public var classAnalyzer : ClassAnalyzer by Delegates.notNull() + + val outputResDir by Delegates.lazy { File(outputResBaseDir, "values") } + + val outputDir by Delegates.lazy { + File(outputBaseDir.getAbsolutePath() + "/" + appPkg.replace('.','/') + "/generated") + } + + val dbrOutputDir by Delegates.lazy { + File(outputBaseDir.getAbsolutePath() + "/" + dbr.pkg.replace('.','/')) + } + + public fun analyzeClasses() { + viewExprBinderRenderers.forEach { + it.lb.analyzeVariables() + } + } + + fun log (s : String) = System.out.println("LOG:$s"); + + public fun process() { + val xmlFiles = ArrayList() + resourceFolders.filter({it.exists()}).forEach { + findLayoutFolders(it).forEach { + findXmlFiles(it, xmlFiles) + } + } + //viewBinderRenderers.clear() + for (xml in xmlFiles) { + log("xmlFile $xml") + val exprBinding = parseXml3(xml) + if (exprBinding == null) { + log("no bindings in $xml, skipping") + continue + } + val vebr = ViewExprBinderRenderer("$appPkg.generated", appPkg, "${toClassName(xml.name)}Binder", toLayoutId(xml.name), exprBinding) + viewExprBinderRenderers.add(vebr) + } + br = BrRenderer("$appPkg.generated", "BR" ,viewExprBinderRenderers) + dbr = DataBinderRenderer("com.android.databinding.library", appPkg, + "GeneratedDataBinderRenderer", viewExprBinderRenderers) + styler = AttrRenderer(viewExprBinderRenderers) + } + + public fun writeAttrFile() { + outputResDir.mkdirs() + writeToFile(File(outputResDir, "bindingattrs.xml"), styler.render()) + } + + public fun writeDbrFile() : Unit = writeDbrFile(dbrOutputDir) + public fun writeDbrFile(dir : File) : Unit { + dir.mkdirs() + writeToFile(File(dir, "${dbr.className}.java"), dbr.render(br)) + } + + public fun writeViewBinderInterfaces() : Unit = writeViewBinderInterfaces(outputDir) + + public fun writeViewBinderInterfaces(dir : File) : Unit { + dir.mkdirs() + viewExprBinderRenderers.forEach({ + writeToFile(File(dir, "${it.interfaceName}.java"), it.renderInterface(br)) + }) + } + + public fun writeBrFile() : Unit = writeBrFile(outputDir) + + public fun writeBrFile(dir : File) : Unit { + dir.mkdirs() + writeToFile(File(dir, "${br.className}.java"), br.render()) + } + public fun writeViewBinders() : Unit = writeViewBinders(outputDir) + public fun writeViewBinders(dir : File) : Unit { + dir.mkdirs() +// viewBinderRenderers.forEach({ +// writeToFile(File(dir, "${it.className}.java"), it.render(br)) +// }) + viewExprBinderRenderers.forEach({ + writeToFile(File(dir, "${it.className}.java"), it.render(br)) + }) + } + + private fun writeToFile(file : File, contents : String) { + System.out.println("output file: ${file.getAbsolutePath()}") + file.writeText(contents) + } + + private fun toClassName(name:String) : String = + name.substring(0, name.indexOf(".")).split("_").map { "${it.substring(0,1).toUpperCase()}${it.substring(1)}" }.join("") + + private fun toLayoutId(name:String) : String = + name.substring(0, name.indexOf(".")) + + private fun parseXml3(xml: File) : LayoutExprBinding? { + val factory = DocumentBuilderFactory.newInstance() + val builder = factory.newDocumentBuilder() + val doc = builder.parse(xml) + val xPathFactory = XPathFactory.newInstance() + val xPath = xPathFactory.newXPath() + // + val layoutBinding = LayoutExprBinding(doc) + val exprParser = ExpressionParser() + val varsExprs = xPath.compile("//@*[starts-with(name(), 'bind_var')]/..") + val varNodes = varsExprs.evaluate(doc, XPathConstants.NODESET) as NodeList + + System.out.println("var node count" + varNodes.getLength()) + for (i in 0..varNodes.getLength() - 1) { + val item = varNodes.item(i) + System.out.println("checking variable node $item") + val attributes = item.getAttributes() + val variableScope = VariableScope(item) + val attrCount = attributes.getLength() + for (j in 0..(attrCount - 1)) { + val attr = attributes.item(j) + val name = attr.getNodeName() + if (name.startsWith("bind_var:")) { + variableScope.variables.add(VariableDefinition(name.substring("bind_var:".length), attr.getNodeValue())) + } + } + layoutBinding.addVariableScope(variableScope) + } + + val expr = xPath.compile("//@*[starts-with(name(), 'bind')]/..") + val nodes = expr.evaluate(doc, XPathConstants.NODESET) as NodeList + System.out.println("binding node count " + nodes.getLength()) + for (i in 0..nodes.getLength() - 1) { + val item = nodes.item(i) + System.out.println("checking node $item") + val attributes = item.getAttributes() + val id = attributes.getNamedItem("android:id") + if (id == null) { + continue + } + val bindingTarget = BindingTarget(item, id.getNodeValue(), getFullViewClassName(item.getNodeName())) + val attrCount = attributes.getLength() + for (j in 0..(attrCount - 1)) { + val attr = attributes.item(j) + val name = attr.getNodeName() + if (name.startsWith("bind:")) { + bindingTarget.addBinding(name.substring("bind:".length), exprParser.parse(attr.getNodeValue())) + } + } + layoutBinding.bindingTargets.add(bindingTarget) + } + + val convExpr = xPath.compile("//@*[starts-with(name(), 'bind_static')]/..") + val convNodes = convExpr.evaluate(doc, XPathConstants.NODESET) as NodeList + System.out.println("converter node count " + nodes.getLength()) + for (i in 0..convNodes.getLength() - 1) { + val item = convNodes.item(i) + System.out.println("checking conv node $item") + val attributes = item.getAttributes() + val attrCount = attributes.getLength() + for (j in 0..(attrCount - 1)) { + val attr = attributes.item(j) + val name = attr.getNodeName() + if (name.startsWith("bind_static:")) { + layoutBinding.addStaticClass(name.substring("bind_static:".length), attr.getNodeValue()) + } + } + } + if (exprParser.model.variables.size == 0) { + return null + } + layoutBinding.exprModel = exprParser.model + layoutBinding.pack() + return layoutBinding + } + + private fun findLayoutFolders(resources: File): Array { + val filenameFilter = object : FilenameFilter { + override fun accept(dir: File, name: String): Boolean { + return name.startsWith("layout") + } + } + return resources.listFiles(filenameFilter) + } + + var xmlFilter: FilenameFilter = object : FilenameFilter { + override fun accept(dir: File, name: String): Boolean { + return name.toLowerCase().endsWith(".xml") + } + } + + private fun findXmlFiles(root: File, out: MutableList) { + if (!root.exists()) { + return + } + if (root.isDirectory()) { + for (file in root.listFiles(xmlFilter)) { + if ("." == file.getName() || ".." == file.getName()) { + continue + } + if (file.isDirectory()) { + findXmlFiles(file, out) + } else if (xmlFilter.accept(file, file.getName())) { + out.add(file) + } + } + } + } + + fun getFullViewClassName(viewName: String): String { + if (viewName.indexOf('.') == -1) { + if (viewName == "View" || viewName == "ViewGroup") { + return "android.view.$viewName" + } + return "android.widget.$viewName" + } + return viewName + } +} diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/parser/expression_parser.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/parser/expression_parser.kt new file mode 100644 index 0000000..bd3d0c4 --- /dev/null +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/parser/expression_parser.kt @@ -0,0 +1,110 @@ +package com.android.databinding.parser + +import org.antlr.v4.runtime.ANTLRInputStream +import com.android.databinding.DataBinderLexer +import org.antlr.v4.runtime.CommonTokenStream +import com.android.databinding.DataBinderParser +import com.android.databinding.parser.ExprModel +import com.android.databinding.DataBinderBaseVisitor +import com.android.databinding.parser.Expr +import com.android.databinding.parser.TernaryExpr +import com.android.databinding.parser.OpExpr +import com.android.databinding.parser.GlobalMethodCallExpr +import com.android.databinding.parser.MethodCallExpr +import com.android.databinding.parser.FieldExpr +import com.android.databinding.parser.VariableRef +import com.android.databinding.parser.SymbolExpr +import com.android.databinding.util.Log + +/** + * Created by yboyar on 11/16/14. + */ +class ExpressionParser { + val model = ExprModel() + val visitor = ExprVisitor(model) + public fun parse(input : String) : Expr { + val inputStream = ANTLRInputStream(input) + val lexer = DataBinderLexer(inputStream) + val tokenStream = CommonTokenStream(lexer) + val parser = DataBinderParser(tokenStream) + val expr = parser.expr() + visitor.accessedVariables.clear() + Log.d("exp tree: ${expr.toStringTree(parser)}") + val parsedExpr = expr.accept(visitor) + parsedExpr.setReferencedVariables(visitor.accessedVariables) + return parsedExpr + } + + fun log(s: String) { + System.out.println("[parser]: $s"); + } +} + +class ExprVisitor(val model : ExprModel) : DataBinderBaseVisitor() { + val accessedVariables = hashSetOf() + //MUST VISIT EVERYTHING IN THE GRAMMAR + override fun visitInnerExpr(ctx: DataBinderParser.InnerExprContext): Expr { + return ctx.inner.accept(this) + } + + override fun visitNilExpr(ctx: DataBinderParser.NilExprContext?): Expr? { + return SymbolExpr("null") + } + + override fun visitTernaryExpr(ctx: DataBinderParser.TernaryExprContext): Expr { + return TernaryExpr(ctx.pred.accept(this), ctx.t.accept(this), ctx.f.accept(this)) + } + + override fun visitOpExpr(ctx: DataBinderParser.OpExprContext): Expr { + return OpExpr(ctx.left.accept(this), ctx.op.getText(), ctx.right.accept(this)) + } + + override fun visitEqExpr(ctx: DataBinderParser.EqExprContext): Expr { + return OpExpr(ctx.left.accept(this), "==", ctx.right.accept(this)) + } + + fun parseExprList(expList : DataBinderParser.ExprListContext?) : List = + if (expList == null) { + arrayListOf() + } + else { + expList.children.filter { it.getText() != "," }.map { it.accept(this) } + } + + override fun visitGlobalMethodCallExpr(ctx: DataBinderParser.GlobalMethodCallExprContext): Expr { + return GlobalMethodCallExpr(ctx.methodName.getText(), parseExprList(ctx.arguments)) + } + + override fun visitMethodCallExpr(ctx: DataBinderParser.MethodCallExprContext): Expr { + return MethodCallExpr(ctx.ownerObj.accept(this), ctx.methodName.getText(), parseExprList(ctx.arguments)) + } + + override fun visitField(ctx: DataBinderParser.FieldContext): Expr { + return toField(ctx) + } + + public fun toField(ctx : DataBinderParser.FieldContext) : FieldExpr { + val fieldVars = arrayListOf() + ctx.children.filterNot{it.getText() == "."}.fold("") { prev, next -> + val name = if (prev == "") next.getText() else "$prev.$next" + val variableRef = model.getOrCreateVariable(name, model.getVariable(prev)) + accessedVariables.add(variableRef) + fieldVars.add(variableRef) + name + } + return FieldExpr(fieldVars[0], fieldVars.drop(1)) + } + + override fun visitAtomExpr(ctx: DataBinderParser.AtomExprContext): Expr? { + return ctx.atom.accept(this) + } + + override fun visitHackyStringExpr(ctx: DataBinderParser.HackyStringExprContext): Expr? { + val s = ctx.getText() + return SymbolExpr("\"${s.substring(1, s.size - 1)}\""); + } + + override fun visitSymbol(ctx: DataBinderParser.SymbolContext): Expr? { + return SymbolExpr(ctx.getText()) + } +} \ No newline at end of file diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/parser/expressions.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/parser/expressions.kt new file mode 100644 index 0000000..196dc43 --- /dev/null +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/parser/expressions.kt @@ -0,0 +1,98 @@ +package com.android.databinding.parser + +import kotlin.properties.Delegates +import java.util.HashSet +import com.android.databinding.vo.Variable +import com.android.databinding.util.Log + +/** + * Created by yboyar on 11/16/14. + */ + +public open class ExprModel { + var start : Expr by Delegates.notNull() + val variables = hashMapOf() + + var rootVariables = HashSet() + + var variableIdGenerator = 0; + + public fun pack() { + variables.mapTo(rootVariables){it.value} + } + public fun getVariable(name : String) : VariableRef? = variables[name] + + public fun getOrCreateVariable(name : String, parent : VariableRef?) : VariableRef = + variables.getOrElse(name, { + Log.d("creating variable for $name") + val variable = VariableRef(variableIdGenerator++, name, parent) + variables.put(name, variable) + variable + }) +} +abstract public class Expr { + // ordered by depth + var referencedVariables = arrayListOf() + fun setReferencedVariables(refs : Collection) { + referencedVariables.clear() + refs.groupBy{it.depth}.toSortedMap().forEach { referencedVariables.addAll(it.value)} + } + abstract fun toReadableString() : String + + abstract fun toJava() : String +} + +public class VariableRef(val id : Int, val fullName: String, val parent : VariableRef? = null) { + var variable : Variable by Delegates.notNull() + val depth : Int by Delegates.lazy { + if (parent == null) { + 1 + } else { + parent.depth + 1 + } + } + override fun toString(): String = "VariableRef(id=$id name=$fullName hasParent:${parent != null})" +} + +public data class SymbolExpr(val text : String) : Expr() { + override fun toJava(): String = text + override fun toReadableString() = text + +} + +public data class FieldExpr(val rootVariable : VariableRef, val subVariables : List) : Expr() { + override fun toJava(): String = if (subVariables.size == 0) rootVariable.variable.localName else subVariables.last!!.variable.localName + + override fun toReadableString(): String = if (subVariables.size == 0) rootVariable.fullName else subVariables.last!!.fullName +} + +public data class GlobalMethodCallExpr(val methodName : String, val args : List) : Expr() { + override fun toJava(): String { + throw UnsupportedOperationException() + } + + override fun toReadableString(): String = "$methodName(" + args.map { it.toReadableString() }.join(",") + ")" + +} + +public data class MethodCallExpr(val owner : Expr, val methodName : String, val args : List) : Expr() { + override fun toJava(): String = + "${owner.toJava()}.$methodName(${args.map{it.toJava()}.join(", ")})" + + override fun toReadableString(): String = "${owner.toReadableString()}.$methodName(" + args.map { it.toReadableString() }.join(",") + ")" + +} + +public data class TernaryExpr(val predicate : Expr, val ifTrue : Expr, val ifFalse : Expr) : Expr() { + override fun toJava(): String = "${predicate.toJava()} ? ${ifTrue.toJava()} : ${ifFalse.toJava()}" + + override fun toReadableString(): String = "${predicate.toReadableString()} ? ${ifTrue.toReadableString()} : ${ifFalse.toReadableString()}" + +} + +public data class OpExpr(val left : Expr, val op : String, val right : Expr) : Expr() { + override fun toJava(): String = "${left.toJava()} $op ${right.toJava()}" + + override fun toReadableString(): String = "${left.toReadableString()} $op ${right.toReadableString()}" + +} \ No newline at end of file diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/attr_renderer.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/attr_renderer.kt new file mode 100644 index 0000000..8d9fb93 --- /dev/null +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/attr_renderer.kt @@ -0,0 +1,29 @@ +/** + * Created by yboyar on 11/10/14. + */ +package com.android.databinding.renderer + +import java.util.TreeSet + + +class AttrRenderer(rs : List) { + val names = TreeSet(); + { + rs.forEach { + it.lb.variables.values().forEach { + names.add(it.name) + } + it.lb.bindings.forEach { + names.add(it.targetFieldName) + } + } + + } + public fun render() : String = """ + + + ${names.map {""}.join("\n ")} + + +""" +} diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/binding_br_renderer.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/binding_br_renderer.kt new file mode 100644 index 0000000..3dda574 --- /dev/null +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/binding_br_renderer.kt @@ -0,0 +1,37 @@ +/** + * Created by yboyar on 11/9/14. + */ +package com.android.databinding.renderer + +import java.util.TreeMap +import java.util.LinkedHashMap + +class BrRenderer(val pkg : String, val className : String, val vbrs : List) { + val keyToInt = LinkedHashMap(); + { + addKey("__") + vbrs.forEach { + it.lb.variables.values().forEach { + addKey(it.name) + } + } + } + var counter = 0 + fun addKey(name : String) { + if (!keyToInt.contains(name)) { + keyToInt.put(name, counter ++) + } + } + + public fun toInt(key : String) : Int = if (key == "") keyToInt.get("__") else keyToInt.get(key) ?: -1 + public fun toIntS(key : String) : String = "${className}.${if (key == "") "__" else key}" + public fun render() : String { + return """ +package $pkg; + +public class $className { + ${keyToInt.map({ "public static final int ${it.key} = ${it.value};"}).joinToString("\n ")} +} +""" + } +} diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/data_binder_renderer.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/data_binder_renderer.kt new file mode 100644 index 0000000..0e69df9 --- /dev/null +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/data_binder_renderer.kt @@ -0,0 +1,32 @@ +/** + * Created by yboyar on 11/8/14. + */ +package com.android.databinding.renderer + +class DataBinderRenderer(val pkg: String, val projectPackage: String, val className: String, val renderers : List ) { + fun render(br : BrRenderer) = +""" +package $pkg; +import $projectPackage.R; +import ${br.pkg}.${br.className}; +public class $className implements com.android.databinding.library.DataBinderMapper { + @Override + public com.android.databinding.library.ViewDataBinder getDataBinder(android.view.View view, int layoutId) { + switch(layoutId) {${renderers.map {""" + case R.layout.${it.layoutName}: + return new ${it.pkg}.${it.className}(view);""" +}.joinToString("\n ")} + } + return null; + } + + @Override + public int getId(String key) { + switch(key) { + ${br.keyToInt.map({ "case \"${it.key}\": return ${br.className}.${it.key};"}).joinToString("\n ")} + } + return -1; + } +} +""" +} diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/view_expr_binder_renderer.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/view_expr_binder_renderer.kt new file mode 100644 index 0000000..7c8586b --- /dev/null +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/renderer/view_expr_binder_renderer.kt @@ -0,0 +1,181 @@ +package com.android.databinding.renderer +import com.android.databinding.renderer.BrRenderer +import com.android.databinding.ext.toCamelCase +import com.android.databinding.ext.times +import com.android.databinding.ext.indent +import com.android.databinding.ext.indentExceptFirst +import com.android.databinding.vo.LayoutExprBinding +import com.android.databinding.vo +import com.android.databinding.ext.toCamelCase +import com.android.databinding.ext.toCamelCaseAsVar +import com.android.databinding.ext.joinIndentedExceptFirst +import com.android.databinding.ext.joinIndented + +/** + * Created by yboyar on 11/17/14. + */ +class ViewExprBinderRenderer(val pkg: String, val projectPackage: String, val baseClassName: String, + val layoutName:String, val lb: LayoutExprBinding) { + val className = "${baseClassName}Impl" + val interfaceName = "${baseClassName}" + val dirtyFlagName = "mDirty" + + fun setChildren(v : vo.Variable) : String = if (v.isPrimitive || v.children.size == 0) "" + else + """if (($dirtyFlagName | ${v.childrenDirtyFlagName}) != 0) { // ${v.childrenDirtyFlagsExpr} + if (${v.localName} != null) { + ${v.children.map{""" + ${it.localName} = ${it.getterOnParentLocal}; + ${if (it.isObservable) { + "updateRegistration(${it.localIdName}, ${it.localName});" + } else ""} + ${setChildren(it).indentExceptFirst(1)} + """}.joinIndented(1)} + } ${if(v.observableDescendents.size == 0) "" else {"""else { + ${v.observableDescendents.map{"updateRegistration(${it.localIdName}, null);"}.joinIndentedExceptFirst(5)} + }"""}} + } +""" + public fun render(br : BrRenderer) : String = +""" +package $pkg; +import $projectPackage.R; +import com.android.databinding.library.Observable; + +public class $className extends com.android.databinding.library.ViewDataBinder + implements $interfaceName { + +private long $dirtyFlagName = -1; + +${lb.rootVariables.values().filterNot{it.static}.map{ + "${it.declare};" +}.joinIndented(1)} + +${lb.bindingTargets.filter { it.bindings.size > 0 }.map { + "${it.viewClass} ${it.resolvedViewName};" }.joinIndented(1) +} + public $className(android.view.View root) { + super(root, ${lb.observableVariables.size}); + ${lb.bindingTargets.filter { it.bindings.size > 0 }.map { "this.${it.resolvedViewName} = (${it.viewClass})root.${it.findViewById};" }.join("\n ") } + } + + public boolean setVariable(int variableId, Object variable){ + switch(variableId) { +${lb.rootVariables.values().filterNot{it.static}.map { variable -> """ + case ${br.toIntS(variable.name)}: { + ${variable.setter}((${variable.klassName}) variable); + return true; + } +"""}.joinIndentedExceptFirst(1)} + } + return false; + } + +${lb.rootVariables.values().filterNot{it.static}.map { variable -> """ + public void ${variable.setter}(${variable.klassName} ${variable.name}) { + ${if (variable.isObservable) { + "updateRegistration(${variable.localIdName}, ${variable.name});" + } else ""} + this.${variable.name} = ${variable.name}; + $dirtyFlagName |= ${variable.dirtyFlagName}; + super.requestRebind(); + } +"""}.joinIndentedExceptFirst(1)} + +${lb.observableVariables.map { variable -> """ + public boolean ${variable.onChange}(${variable.klassName} ${variable.name}, int fieldId) { + switch (fieldId) { + ${variable.children.map{""" + case ${br.toIntS(it.name)}: { + $dirtyFlagName |= ${it.dirtyFlagName}; + return true; + }"""}.joinIndentedExceptFirst(1)} + case ${br.toIntS("")}: + $dirtyFlagName |= ${variable.dirtyFlagName}; + return true; + } + return false; + } +"""}.joinIndentedExceptFirst(1)} + + @Override + protected boolean onFieldChange(int mLocalFieldId, Object object, int fieldId) { + switch (mLocalFieldId) { + // TODO also handle non-observables. basically, set them + ${lb.observableVariables.map {""" + case ${it.localIdName} : + return ${it.onChange}((${it.klassName})object, fieldId); + """}.joinIndentedExceptFirst(1)} + } + return false; + } + +${lb.bindingTargets.filter { it.bindings.size > 0 }.map { """ + @Override + public ${it.viewClass} get${it.resolvedUniqueName}() { + return this.${it.resolvedViewName}; + }"""}.joinIndentedExceptFirst(1) } + + @Override + public void rebindDirty() { + final long dirty = $dirtyFlagName; + $dirtyFlagName = 0L; // mark everything non dirty + ${lb.dynamicVariables.filterNot{it.isRootVariable}.map{ + "${it.declareLocal}${"= ${it.defaultValue}"};" + }.joinIndentedExceptFirst(2)} + + // collect variables that exist + ${lb.rootVariables.filterNot{it.value.static}.map { + setChildren(it.value)}.joinIndentedExceptFirst(3) + } + // TODO find common ancestor from bound variables and do this binding in its setter. + // common ancestor might be null in which case we should do it here. + // we can even avoid checking another dirty here if it exactly matches the variable scope + // (unlikely because it is probably a field) + ${lb.bindings.map { binding -> """ + if ( (dirty & (${binding.isDirtyName})) != 0 ) { + // ${binding.expr.toReadableString()} + ${binding.target.resolvedViewName}.${binding.setter}(${binding.expr.toJava()}); + }"""}.joinIndented(2)} + } + +${lb.observableVariables.map { + "private static final int ${it.localIdName} = ${it.localId};" +}.joinIndented(1)} + +${lb.dynamicVariables.map { + "private static final long ${it.dirtyFlagName} = ${it.dirtyFlag}L;" +}.joinIndented(1)} + +${lb.dynamicVariables.map { + "private static final long ${it.childrenDirtyFlagName} = ${it.childrenDirtyFlagsExpr};" +}.joinIndented(1)} + +${lb.bindings.map { + "private static final long ${it.isDirtyName} = ${it.isDirtyExpr};" +}.joinIndented(1)} + +/** +${lb.bindingTargets.map{ target -> + target.bindings.map { binding -> + "${binding.expr.toReadableString()}" + }.joinIndentedExceptFirst(1) +}.joinIndentedExceptFirst(2)} +**/ +} +""" + + public fun renderInterface(br : BrRenderer) : String = + """ +package $pkg; + +public interface ${interfaceName} extends com.android.databinding.library.IViewDataBinder { +${lb.rootVariables.values().filterNot{it.static}.map { variable -> """ + public void ${variable.setter}(${variable.klassName} ${variable.name}); +"""}.joinIndentedExceptFirst(1)} +${lb.bindingTargets.filter { it.bindings.size > 0 }.map { """ + public ${it.viewClass} get${it.resolvedUniqueName}();"""}.joinIndentedExceptFirst(1) } +} +""" + +} \ No newline at end of file diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/Log.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/Log.kt new file mode 100644 index 0000000..111d1d5 --- /dev/null +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/Log.kt @@ -0,0 +1,7 @@ +package com.android.databinding.util + +object Log { + fun d(s : String) { + System.out.println("[debug] $s") + } +} \ No newline at end of file diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/class_analyzer.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/class_analyzer.kt new file mode 100644 index 0000000..4de4765 --- /dev/null +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/class_analyzer.kt @@ -0,0 +1,117 @@ +package com.android.databinding.util + +import java.net.URLClassLoader +import kotlin.properties.Delegates +import com.android.databinding.ext.toCamelCase +import com.android.databinding.util.Log +import java.lang.reflect.Modifier + +/** + * Created by yboyar on 11/12/14. + */ +public fun Class<*>.isObservable() : Boolean = ClassAnalyzer.instance.observable.isAssignableFrom(this) + +public fun Class<*>.getCodeName() : String = getName().replace("$", ".") + +public fun Class<*>.getMethodOrField(identifier : String) : Pair { + val getterName = "get${identifier.toCamelCase()}" + try { + val method = getDeclaredMethod(getterName) + if (Modifier.isPublic(method.getModifiers())) { + return Pair("$getterName()", method.getReturnType().getCodeName()) + } + } catch(t : Throwable){ + Log.d("exp: ${t.getMessage()}") + } + try { + val field = getDeclaredField(identifier) + if (Modifier.isPublic(field.getModifiers())) { + return Pair("$identifier", field.getType().getCodeName()) + } + } catch(t : Throwable){ + Log.d("exp: ${t.getMessage()}") + } + throw IllegalArgumentException("cannot find $identifier or $getterName() on ${this.getSimpleName()}") +} + +class ClassAnalyzer(val classLoader : URLClassLoader) { + { + instance = this + } + val loadedClasses = hashMapOf>() + val observable = loadClass("com.android.databinding.library.Observable"); + + class object { + var instance : ClassAnalyzer by Delegates.notNull() + } + + fun loadPrimitive(className : String) : Class<*>? { + if("int" == className) { + return javaClass() + } + if("short".equals(className)) { + return javaClass() + } + if("long".equals(className)) { + return javaClass() + } + if("float".equals(className)) { + return javaClass() + } + if("double".equals(className)) { + return javaClass() + } + if("boolean".equals(className)) { + return javaClass() + } + return null + } + + fun getDefaultValue(className : String) : String { + if("int" == className) { + return "0"; + } + if("short".equals(className)) { + return "0"; + } + if("long".equals(className)) { + return "0L" + } + if("float".equals(className)) { + return "0fL"; + } + if("double".equals(className)) { + return "0.0"; + } + if("boolean".equals(className)) { + return "false"; + } + return "null"; + } + + fun loadClass(klassName : String) : Class<*> { + var loaded = loadedClasses[klassName] ?: loadPrimitive(klassName) + if (loaded == null) { + loaded = loadRecursively(klassName) + System.out.println("loaded ${loaded}") + loaded!!.getInterfaces().forEach { + System.out.println("interfaces ${it}") + } + loadedClasses.put(klassName, loaded) + } + return loaded!! + } + + fun loadRecursively(klassName : String) : Class<*> { + System.out.println("trying to find class ${klassName}") + try { + return classLoader.loadClass(klassName) + } catch(ex : ClassNotFoundException) { + val lastIndexOfDot = klassName.lastIndexOf(".") + if (lastIndexOfDot == -1) { + throw ex; + } + return loadRecursively("${klassName.substring(0, lastIndexOfDot)}\$${klassName.substring(lastIndexOfDot + 1)}") + } + } +} \ No newline at end of file diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/vo/vo.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/vo/vo.kt new file mode 100644 index 0000000..04814f2 --- /dev/null +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/vo/vo.kt @@ -0,0 +1,256 @@ +package com.android.databinding.vo + +import com.android.databinding.parser.ExprModel +import kotlin.properties.Delegates +import org.w3c.dom.Node +import com.android.databinding.parser.Expr +import java.util.TreeMap +import com.android.databinding.parser.VariableRef +import com.android.databinding.ext.toCamelCase +import com.android.databinding.ext.joinToCamelCase +import com.android.databinding.ext.extractAndroidId +import com.android.databinding.ext.getAndroidIdPath +import com.android.databinding.util.ClassAnalyzer +import com.android.databinding.util.getMethodOrField +import com.android.databinding.util.Log +import com.android.databinding.ext.joinToCamelCaseAsVar +import com.android.databinding.util.isObservable + +/** + * Created by yboyar on 11/17/14. + */ + +class Binding(val target : BindingTarget, val targetFieldName : String, val expr : Expr) { + // which variables effect the result of this binding + // ordered by depth + val relatedVariables : List by Delegates.lazy { + expr.referencedVariables.map {it.variable} + } + + val isDirtyExpr : String by Delegates.lazy { + relatedVariables.map {it.dirtyFlagName}.join(" | ") + } + + val setter = "set${targetFieldName.capitalize()}" + + val isDirtyName by Delegates.lazy {"sDirtyFlag${target.resolvedUniqueName}_${targetFieldName.capitalize()}"} +} + +data class BindingTarget(val node: Node, val id: String, val viewClass: String) { + val bindings = arrayListOf() + public fun addBinding(fieldName : String, expr : Expr) { + bindings.add(Binding(this, fieldName, expr)) + } + val rId:String by Delegates.lazy { "R.id.$idName" } + val idName by Delegates.lazy { id.extractAndroidId() } + var resolvedUniqueName : String by Delegates.notNull() + val resolvedViewName by Delegates.lazy{"m${resolvedUniqueName}"} + val idNamePath by Delegates.lazy {node.getAndroidIdPath(false).reverse().map {it.extractAndroidId()}} + val findViewById by Delegates.lazy { + idNamePath.map {"findViewById(R.id.$it)"}.join(".") + } +} + +data class Variable(val fullName : String, val parent : Variable? = null) { + var static : Boolean = false + var localId : Int by Delegates.notNull() // assigned if and only if variable is non-static observable + val path = fullName.split("\\.") + val name = path.last() + var uniqueName = fullName // TODO change if we support variables w/ the same name + var klassName : String by Delegates.notNull() + val children = arrayListOf() + val observableChildren by Delegates.lazy {children.filter{it.isObservable}} + val descendents : List by Delegates.lazy {children + children.flatMap{it.descendents}} + val observableDescendents : List by Delegates.lazy {descendents.filter{it.isObservable}} + var isRootVariable = false + val defaultValue by Delegates.lazy { ClassAnalyzer.instance.getDefaultValue(klassName)} + val resolvedClass : Class<*> by Delegates.lazy { + ClassAnalyzer.instance.loadClass(klassName) + } + val getter : String by Delegates.lazy { + if (parent == null) { + name + } else { + val pair = parent.resolvedClass.getMethodOrField(name) + klassName = pair.second + pair.first + } + } + val fullCamelCase = uniqueName.split("\\.").joinToCamelCase() + // has to be lazy to get up to date static value + // TODO handle final pbulic instead! + val localName by Delegates.lazy {if (static) getterGlobal else "${uniqueName.split("\\.").joinToCamelCaseAsVar()}" } + val localIdName by Delegates.lazy { if(localId > -1) "s$fullCamelCase" else "" }//just adding a reference to localId to detect errors + val dirtyFlag : Int by Delegates.lazy { (Math.pow(2.toDouble(), localId.toDouble())).toInt() } + val dirtyFlagName by Delegates.lazy {if (static) "0" else "flag$fullCamelCase"} + val variablePath : List by Delegates.lazy { + if (parent == null) arrayListOf(this) else parent.variablePath + arrayListOf(this) + } + val isDirtyExpr : String by Delegates.lazy { + variablePath.map {it.dirtyFlagName}.join(" | ") + } + + val childrenDirtyFlagsExpr: String by Delegates.lazy { + (children.map{it.childrenDirtyFlagsExpr } + arrayListOf(dirtyFlagName)).join(" | ") + } + + val isDirtyName : String = "isDirty$fullCamelCase" + + val childrenDirtyFlagName: String = "flagHasDirtyChild$fullCamelCase" + + val onChange : String by Delegates.lazy { "onChange$fullCamelCase"} + + val declare : String by Delegates.lazy { "$klassName $name" } + + val declareLocal : String by Delegates.lazy { "$klassName $localName" } + + val isObservable : Boolean by Delegates.lazy { + resolvedClass.isObservable() + } + + val isPrimitive : Boolean by Delegates.lazy {resolvedClass.isPrimitive()} + + val setter by Delegates.lazy {"set$fullCamelCase"} + + val getterGlobal : String by Delegates.lazy { + if (parent == null) { + if (static) { + klassName + } else { + "this.$name" + } + } else { + "${parent.getterGlobal}.$getter" + } + } + + val getterOnParentLocal by Delegates.lazy { + if (parent == null) { + if (static) { + klassName + } else { + "this.$name" + } + } else { + "${parent.localName}.$getter" + } + } + + fun markAsStatic() { + static = true + children.forEach{it.markAsStatic()} + } +} + +open data class VariableDefinition(val name : String, val klass : String, val static : Boolean = false) + +data class VariableScope(val node : Node, val variables : MutableList = arrayListOf()) + +data class StaticClass(name : String, klass : String) : VariableDefinition(name, klass, true) + +data class LayoutExprBinding(val root : Node) { + var exprModel : ExprModel by Delegates.notNull() + val variableScopes = hashMapOf() + val bindingTargets = arrayListOf() + val variables = TreeMap() + val rootVariables = hashMapOf() + val dynamicVariables : List by Delegates.lazy {variables.values().filterNot{it.static}} + val observableVariables by Delegates.lazy {dynamicVariables.filter{it.isObservable}} + val bindings by Delegates.lazy { + bindingTargets.flatMap{it.bindings} + } + + val staticVariableScope : VariableScope by Delegates.lazy { + var existing = variableScopes[root] + if (existing == null) { + existing = VariableScope(root) + variableScopes.put(root, existing) + } + existing!! + } + + public fun addVariableScope(scope : VariableScope) { + if (variableScopes.put(scope.node, scope) != null) { + throw IllegalArgumentException("duplicate scope created for node ${scope.node}") + } + } + + public fun addStaticClass(name : String, klass : String) { + staticVariableScope.variables.add(VariableDefinition(name, klass, true)) + } + + private fun toVariable(ref : VariableRef, klassLookup : Map) : Variable { + var existing = variables[ref.fullName] + if (existing != null) { + return existing + } + var parent = if (ref.parent == null) null else toVariable(ref.parent, klassLookup) + existing = Variable(ref.fullName, parent) + if (parent == null) { + existing.klassName = klassLookup[existing.fullName]!! + rootVariables[ref.fullName] = existing + existing.isRootVariable = true + } else { + parent!!.children.add(existing) + } + + variables[ref.fullName] = existing + ref.variable = existing + return existing + } + + fun pack() { + exprModel.pack() //seal the model, nothing will be added after this + + // assign klass to root variables that we can + val rootVariableKlasses = TreeMap() + val staticVariableKlasses = TreeMap() + variableScopes.forEach { + it.value.variables.forEach { + if (rootVariableKlasses.put(it.name, it.klass) != null) { + throw IllegalArgumentException("two variables cannot share the same name yet") + } + if (it.static) { + staticVariableKlasses.put(it.name, it.klass) + } + } + } + + // convert variable references to variables + exprModel.variables.forEach { entry -> + Log.d("converting ${entry.value} to variable") + toVariable(entry.value, rootVariableKlasses) + } + + rootVariables.values().forEach { + if (staticVariableKlasses.contains(it.name)) { + it.markAsStatic() + } + } + + // assign unique names to views + bindingTargets.groupBy{ it.idName }.forEach { + if (it.value.size() == 1) { + it.value[0].resolvedUniqueName = "${it.value[0].idName.toCamelCase()}" + } else { + it.value.forEach { + it.resolvedUniqueName = "${it.idNamePath.joinToCamelCase()}" + } + } + } + } + + public fun analyzeVariables() { + variables.forEach { + Log.d("resolving method for ${it.key}") + it.value.getter + Log.d("resolved method / field for ${it.key} is ${it.value.getter} of type ${it.value.klassName}") + } + + // set ids on observables first then in other variables + // observable ids are used for observer references which is why they get first ids + var id = 0 + observableVariables.forEach { it.localId = id++ } + dynamicVariables.filterNot { it.isObservable }.forEach { it.localId = id++ } + } +} \ No newline at end of file diff --git a/tools/data-binding/compiler/src/main/resources/META-INF/gradle-plugins/com.android.databinding.properties b/tools/data-binding/compiler/src/main/resources/META-INF/gradle-plugins/com.android.databinding.properties new file mode 100644 index 0000000..ada6a54 --- /dev/null +++ b/tools/data-binding/compiler/src/main/resources/META-INF/gradle-plugins/com.android.databinding.properties @@ -0,0 +1 @@ +implementation-class=com.android.databinding.DataBinderPlugin \ No newline at end of file diff --git a/tools/data-binding/gradle.properties b/tools/data-binding/gradle.properties new file mode 100644 index 0000000..e9779a3 --- /dev/null +++ b/tools/data-binding/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.daemon=true +#org.gradle.fork=true +org.gradle.jvmargs=-XX:MaxPermSize=512m -Xmx1024m -Dfile.encoding=UTF-8 \ No newline at end of file diff --git a/tools/data-binding/gradle/wrapper/gradle-wrapper.jar b/tools/data-binding/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..3d0dee6 Binary files /dev/null and b/tools/data-binding/gradle/wrapper/gradle-wrapper.jar differ diff --git a/tools/data-binding/gradle/wrapper/gradle-wrapper.properties b/tools/data-binding/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..43e2898 --- /dev/null +++ b/tools/data-binding/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Nov 18 17:13:29 PST 2014 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=http\://services.gradle.org/distributions/gradle-2.1-all.zip diff --git a/tools/data-binding/gradlePlugin/build.gradle b/tools/data-binding/gradlePlugin/build.gradle new file mode 100644 index 0000000..9219bfb --- /dev/null +++ b/tools/data-binding/gradlePlugin/build.gradle @@ -0,0 +1,35 @@ +apply plugin: 'java' +apply plugin: "kotlin" +apply plugin: 'maven' +buildscript { + repositories { + mavenLocal() + mavenCentral() + } + dependencies { + classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:0.9.206' + } +} + +repositories { + mavenCentral() + mavenLocal() +} + +dependencies { + compile 'com.android.tools.build:gradle:0.14.2' + compile 'org.jetbrains.kotlin:kotlin-stdlib:0.9.206' + compile gradleApi() + compile 'commons-io:commons-io:2.4' + compile 'com.android.databinding:compiler:0.2-SNAPSHOT' +} +uploadArchives { + repositories { + mavenDeployer { + repository(url: mavenLocal().url) + pom.version = '0.2-SNAPSHOT' + pom.artifactId = 'dataBinder' + pom.groupId='com.android.databinding' + } + } +} \ No newline at end of file diff --git a/tools/data-binding/gradlePlugin/src/main/kotlin/plugin.kt b/tools/data-binding/gradlePlugin/src/main/kotlin/plugin.kt new file mode 100644 index 0000000..55fa214 --- /dev/null +++ b/tools/data-binding/gradlePlugin/src/main/kotlin/plugin.kt @@ -0,0 +1,231 @@ +package com.android.databinding + +import org.gradle.api.Plugin +import org.gradle.api.Project +import groovy.lang.Closure +import org.codehaus.groovy.runtime.MethodClosure +import org.gradle.api.Task +import com.android.build.gradle.AppExtension +import com.android.build.gradle.internal.api.ApplicationVariantImpl +import com.android.build.gradle.internal.variant.ApplicationVariantData +import com.android.databinding.KLayoutParser +import kotlin.properties.Delegates +import java.net.URLClassLoader +import groovy.lang.MetaClass +import java.io.File +import java.util.ArrayList +import org.gradle.api.internal.tasks.compile.DefaultJavaCompileSpec +import org.gradle.api.tasks.WorkResult +import org.gradle.api.file.FileCollection +import org.gradle.api.internal.file.DefaultSourceDirectorySet +import org.gradle.api.tasks.compile.CompileOptions +import org.gradle.internal.Factory +import org.gradle.api.AntBuilder +import org.gradle.api.internal.project.ProjectInternal +import org.gradle.api.internal.tasks.compile.daemon.CompilerDaemonManager +import org.gradle.api.internal.tasks.compile.DefaultJavaCompilerFactory +import javax.tools.JavaCompiler +import javax.tools.ToolProvider +import java.util.Arrays +import org.apache.commons.io.FileUtils +import com.android.databinding.util.ClassAnalyzer + +class DataBinderPlugin : Plugin { + var parser: KLayoutParser by Delegates.notNull() + var project : Project by Delegates.notNull() + + var generatedBinderSrc : File by Delegates.notNull() + + var generatedBinderOut : File by Delegates.notNull() + + var androidJar : File by Delegates.notNull() + + var variantData : ApplicationVariantData by Delegates.notNull() + + val testOut by Delegates.lazy { + File("app/build/databinder") + } + var viewBinderSource : File by Delegates.notNull() + val viewBinderCompileOutput by Delegates.lazy { File(testOut, "out") } + + override fun apply(project: Project?) { + if (project == null) return + val generateAttr = MethodClosure(this, "generateAttr") + val generateBrFile = MethodClosure(this, "generateBrFile") + val generateBinders = MethodClosure(this, "generateBinders") + this.project = project + project.afterEvaluate { + // TODO read from app + val variants = arrayListOf("Debug") + parser = createKParser(project) + parser.process() + log("after eval") + //processDebugResources + variants.forEach { variant -> + val preTasks = it.getTasksByName("pre${variant}Build", true) + preTasks.forEach { + it.doLast (generateAttr) + } + val processResTasks = it.getTasksByName("process${variant}Resources", true) + processResTasks.forEach { + it.doFirst (generateAttr) + } + val generateSourcesTasks = it.getTasksByName("generate${variant}Sources", true) + log("generate sources tasks ${generateSourcesTasks}") + generateSourcesTasks.forEach { + it.doFirst(generateBrFile) + } + + val compileTasks = it.getTasksByName("compile${variant}Java", true) + log("compile tasks ${compileTasks}") + compileTasks.forEach { + it.doFirst(MethodClosure(this, "cleanBinderOutFolder")) + it.doFirst(generateBinders) + } + } + } + } + + fun log(s: String) { + System.out.println("PLOG: $s") + } + + fun createKParser(p: Project): KLayoutParser { + val ss = p.getExtensions().getByName("android") as AppExtension + androidJar = File(ss.getSdkDirectory().getAbsolutePath() + "/platforms/${ss.getCompileSdkVersion()}/android.jar") + log("creating parser!") + val clazz = javaClass() + val field = clazz.getDeclaredField("variantData") + field.setAccessible(true) + var appVariant = ss.getApplicationVariants().first { it is ApplicationVariantImpl } + variantData = field.get(appVariant) as ApplicationVariantData + + + // TODO + val packageName = variantData.generateRClassTask.getPackageForR() + //"com.com.android.databinding.android.databinding.libraryGen"//variantData.getPackageName() + // + val sources = variantData.getJavaSources() + sources.forEach({ + log("source: ${it}"); + }) + val resourceFolders = variantData.mergeResourcesTask.getRawInputFolders() + //TODO + val codeGenTargetFolder = variantData.generateRClassTask.getSourceOutputDir() + val resGenTargetFolder = variantData.generateRClassTask.getResDir() +// variantData.getExtraGeneratedSourceFolders().forEach { +// log("extra source gen folder ${it}") +// } +// val codeGenTargetFolder = File(sources[2].toString())//File("/Users/yboyar/Desktop/tmp/binding")//variantData.processResourcesTask.getSourceOutputDir() +// val resGenTargetFolder = File(sources[2].toString())//File("/Users/yboyar/Desktop/tmp/binding")//variantData.processResourcesTask.getResDir() + variantData.addJavaSourceFoldersToModel(codeGenTargetFolder) + val jCompileTask = variantData.javaCompileTask + val dexTask = variantData.dexTask + val options = jCompileTask.getOptions() + log("compile options: ${options.optionMap()}") + viewBinderSource = File(testOut.getAbsolutePath() + "/src/" + packageName.split("\\.").join("/")) + viewBinderSource.mkdirs() + variantData.registerJavaGeneratingTask(project.task("dataBinderDummySourceGenTask", MethodClosure(this,"dummySourceGenTask" )), File(testOut.getAbsolutePath() + "/src/")) + viewBinderCompileOutput.mkdirs() + log("view binder source will be ${viewBinderSource}") + log("adding out dir to input files ${viewBinderCompileOutput}") + var inputFiles = dexTask.getInputFiles() + var inputDir = dexTask.getInputDir() + log("current input files for dex are ${inputFiles} or dir ${inputDir}") + if (inputDir != null && inputFiles == null) { + inputFiles = arrayListOf(inputDir) + dexTask.setInputDir(null) + } + inputFiles.add(viewBinderCompileOutput) + dexTask.setInputFiles(inputFiles) + log("updated dexTask input files ${dexTask.getInputFiles()} vs ${inputFiles} vs dir ${dexTask.getInputDir()}") + + dexTask.doFirst(MethodClosure(this, "preDexAnalysis")) + return KLayoutParser(packageName, resourceFolders, codeGenTargetFolder, resGenTargetFolder) + } + + + + fun dummySourceGenTask(o : Any?) { + System.out.println("running dummySourceGenTask") + } + + fun preDexAnalysis(o : Any?) { + val jCompileTask = variantData.javaCompileTask + val dexTask = variantData.dexTask + log("dex task files: ${dexTask.getInputFiles()} ${dexTask.getInputFiles().javaClass}") + log("compile CP: ${jCompileTask.getClasspath().getAsPath()}") + //TODO get from target sdk + //val jarUrl = File("/Users/yboyar/android/sdk/platforms/android-21/android.jar").toURI().toURL() + val jarUrl = androidJar.toURI().toURL() + val androidClassLoader = URLClassLoader(array(jarUrl)) + val cpFiles = arrayListOf() + cpFiles.addAll(dexTask.getInputFiles()) + cpFiles.addAll(jCompileTask.getClasspath().getFiles()) + val urls = cpFiles.map { it.toURI().toURL() }.copyToArray() + log("generated urls: ${urls} len: ${urls.size}") + val classLoader = URLClassLoader(urls, androidClassLoader) + parser.classAnalyzer = ClassAnalyzer(classLoader) + project.task("compileGenerated", MethodClosure(this, "compileGenerated")) + } + fun compileGenerated(o : Any?) { + val compiler = ToolProvider.getSystemJavaCompiler() + val fileManager = compiler.getStandardFileManager(null, null, null) + val javaCompileTask = variantData.javaCompileTask + val dexTask = variantData.dexTask + parser.analyzeClasses() + parser.writeViewBinders(viewBinderSource) + parser.writeDbrFile(viewBinderSource) + + + viewBinderCompileOutput.mkdirs() + val cpFiles = arrayListOf() +// val jarUrl = File("/Users/yboyar/android/sdk/platforms/android-21/android.jar") +// log ("jarURL ${jarUrl.getAbsolutePath()} vs androidJar: ${androidJar.getAbsolutePath()}") + cpFiles.addAll(dexTask.getInputFiles()) + cpFiles.addAll(javaCompileTask.getClasspath().getFiles()) + cpFiles.add(javaCompileTask.getDestinationDir()) + cpFiles.add(androidJar) + val filesToCompile = viewBinderSource.listFiles().map { it.getAbsolutePath() } + log("files to compile ${filesToCompile}") + val fileObjects = fileManager.getJavaFileObjectsFromStrings(filesToCompile) + val optionList = arrayListOf() + // set compiler's classpath to be same as the runtime's + optionList.addAll(Arrays.asList("-classpath",cpFiles.map{it.getAbsolutePath()}.join(":"))) + optionList.add("-verbose") + optionList.add("-d") + optionList.add(viewBinderCompileOutput.getAbsolutePath()) + log("compile options: ${optionList}") + val javac = compiler.getTask(null, fileManager, null, optionList, null, fileObjects) as JavaCompiler.CompilationTask + val compileResult = javac.call() + + if (!compileResult) { + throw RuntimeException("cannot compile generated files. see error for details") + } + } + + fun generateAttr(o: Any?) { + log("generate attr ${o}") + parser.writeAttrFile() + } + + fun cleanBinderOutFolder(o : Any?) { + log("cleaning out folder pre-compile of $o") + viewBinderSource.mkdirs() + FileUtils.cleanDirectory(viewBinderSource) + viewBinderCompileOutput.mkdirs() + FileUtils.cleanDirectory(viewBinderCompileOutput) + } + + fun generateBrFile(o: Any?) { + log("generating BR ${o}") + parser.writeBrFile() + parser.writeViewBinderInterfaces() + } + + fun generateBinders(o: Any?) { + log("generating binders ${o}") +// parser.writeViewBinders() +// parser.writeDbrFile() + } +} diff --git a/tools/data-binding/gradlew b/tools/data-binding/gradlew new file mode 100755 index 0000000..91a7e26 --- /dev/null +++ b/tools/data-binding/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/tools/data-binding/grammerBuilder/DataBinder.g4 b/tools/data-binding/grammerBuilder/DataBinder.g4 new file mode 100644 index 0000000..8a52df9 --- /dev/null +++ b/tools/data-binding/grammerBuilder/DataBinder.g4 @@ -0,0 +1,104 @@ +grammar DataBinder; + +start : expr ; + +expr + : nil #nilExpr + | '(' inner=expr ')' #innerExpr + | ownerObj=expr '.' methodName=Identifier '(' arguments=exprList? ')' #methodCallExpr + | methodName=Identifier '(' arguments=exprList? ')' #globalMethodCallExpr + | atomString=hackyStringSymbol#hackyStringExpr + | atom=symbol#atomExpr + | field #idExpr + | left=expr op=('*'|'/') right=expr #opExpr + | left=expr op=('+'|'-') right=expr #opExpr + | left=expr '==' right=expr #eqExpr + | pred=expr '?' t=expr ':' f=expr #ternaryExpr + ; + +exprList + : expr (',' expr)* + ; + +//methodCall + //: ownerObj=field '.' methodName=Identifier '(' arguments=exprList? ')' #methodCallOnFieldExpr + //| ownerMethod=methodCall '.' methodName=Identifier '(' arguments=exprList? ')' #methodCallOnMethodExpr + //| methodName=Identifier '(' arguments=exprList? ')' #globalMethodCallExpr + //: ownerObj=expr '.' methodName=Identifier '(' arguments=exprList? ')' #methodCallOnFieldExpr + //; + +field + : name=Identifier ('.' Identifier)* + ; + +Identifier + : JavaLetter JavaLetterOrDigit* + ; + +hackyStringSymbol + : HackyStringLiteral + ; + +symbol + : INT + | BOOLEAN + | StringLiteral + | CharacterLiteral + ; + +INT : ('0'..'9')+ ; + +BOOLEAN : ('true'|'false'); + +nil: 'null'; + +fragment +JavaLetter + : [a-zA-Z$_] // these are the "java letters" below 0xFF + | // covers all characters above 0xFF which are not a surrogate + ~[\u0000-\u00FF\uD800-\uDBFF] + {Character.isJavaIdentifierStart(_input.LA(-1))}? + | // covers UTF-16 surrogate pairs encodings for U+10000 to U+10FFFF + [\uD800-\uDBFF] [\uDC00-\uDFFF] + {Character.isJavaIdentifierStart(Character.toCodePoint((char)_input.LA(-2), (char)_input.LA(-1)))}? + ; + +fragment +JavaLetterOrDigit + : [a-zA-Z0-9$_] // these are the "java letters or digits" below 0xFF + | // covers all characters above 0xFF which are not a surrogate + ~[\u0000-\u00FF\uD800-\uDBFF] + {Character.isJavaIdentifierPart(_input.LA(-1))}? + | // covers UTF-16 surrogate pairs encodings for U+10000 to U+10FFFF + [\uD800-\uDBFF] [\uDC00-\uDFFF] + {Character.isJavaIdentifierPart(Character.toCodePoint((char)_input.LA(-2), (char)_input.LA(-1)))}? + ; + +HackyStringLiteral + : '`' StringCharacters? '`' + ; +StringLiteral + : '"' StringCharacters? '"' + ; + +CharacterLiteral + : '\'' SingleCharacter '\'' + ; + +fragment +SingleCharacter + : ~['\\] + ; + +fragment +StringCharacters + : StringCharacter+ + ; + +fragment +StringCharacter + : ~["\\] + ; + + +WS : [ \t\r\n]+ -> skip ; diff --git a/tools/data-binding/grammerBuilder/build.gradle b/tools/data-binding/grammerBuilder/build.gradle new file mode 100644 index 0000000..d793729 --- /dev/null +++ b/tools/data-binding/grammerBuilder/build.gradle @@ -0,0 +1,49 @@ +apply plugin: 'java' +apply plugin:'application' +apply plugin: 'maven' + +sourceCompatibility = 1.5 +version = '1.0' + +mainClassName = "org.antlr.v4.Tool" + +buildscript { + repositories { + mavenLocal() + mavenCentral() + } +} + + +repositories { + mavenCentral() +} + +run { + args "DataBinder.g4", "-visitor", "-o", "src/main/java-gen/com/android/databinding", "-package", "com.android.databinding" +} + +dependencies { + testCompile 'junit:junit:4.11' + compile 'com.tunnelvisionlabs:antlr4:4.4' +} + +sourceSets { + main { + java { + srcDir 'src/main/java' + srcDir 'src/main/java-gen' + } + } +} + +uploadArchives { + repositories { + mavenDeployer { + repository(url: mavenLocal().url) + pom.version = '0.1-SNAPSHOT' + pom.artifactId = 'grammerBuilder' + pom.groupId='com.android.databinding' + } + } +} diff --git a/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinder.tokens b/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinder.tokens new file mode 100644 index 0000000..3696716 --- /dev/null +++ b/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinder.tokens @@ -0,0 +1,31 @@ +StringLiteral=17 +HackyStringLiteral=16 +WS=19 +BOOLEAN=15 +T__11=1 +CharacterLiteral=18 +T__1=11 +T__0=12 +T__10=2 +T__3=9 +T__2=10 +INT=14 +T__9=3 +T__8=4 +Identifier=13 +T__7=5 +T__6=6 +T__5=7 +T__4=8 +'?'=12 +'=='=11 +'/'=10 +':'=9 +'('=8 +'-'=7 +'*'=6 +'+'=5 +','=4 +'.'=3 +')'=2 +'null'=1 diff --git a/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderBaseListener.java b/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderBaseListener.java new file mode 100644 index 0000000..51f2fee --- /dev/null +++ b/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderBaseListener.java @@ -0,0 +1,261 @@ +// Generated from DataBinder.g4 by ANTLR 4.4 +package com.android.databinding; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.misc.NotNull; +import org.antlr.v4.runtime.tree.ErrorNode; +import org.antlr.v4.runtime.tree.TerminalNode; + +/** + * This class provides an empty implementation of {@link DataBinderListener}, + * which can be extended to create a listener which only needs to handle a subset + * of the available methods. + */ +public class DataBinderBaseListener implements DataBinderListener { + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterSymbol(@NotNull DataBinderParser.SymbolContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitSymbol(@NotNull DataBinderParser.SymbolContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterIdExpr(@NotNull DataBinderParser.IdExprContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitIdExpr(@NotNull DataBinderParser.IdExprContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterAtomExpr(@NotNull DataBinderParser.AtomExprContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitAtomExpr(@NotNull DataBinderParser.AtomExprContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterExpr(@NotNull DataBinderParser.ExprContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitExpr(@NotNull DataBinderParser.ExprContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterTernaryExpr(@NotNull DataBinderParser.TernaryExprContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitTernaryExpr(@NotNull DataBinderParser.TernaryExprContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterGlobalMethodCallExpr(@NotNull DataBinderParser.GlobalMethodCallExprContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitGlobalMethodCallExpr(@NotNull DataBinderParser.GlobalMethodCallExprContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterInnerExpr(@NotNull DataBinderParser.InnerExprContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitInnerExpr(@NotNull DataBinderParser.InnerExprContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterField(@NotNull DataBinderParser.FieldContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitField(@NotNull DataBinderParser.FieldContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterOpExpr(@NotNull DataBinderParser.OpExprContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitOpExpr(@NotNull DataBinderParser.OpExprContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterNilExpr(@NotNull DataBinderParser.NilExprContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitNilExpr(@NotNull DataBinderParser.NilExprContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterStart(@NotNull DataBinderParser.StartContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitStart(@NotNull DataBinderParser.StartContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterHackyStringSymbol(@NotNull DataBinderParser.HackyStringSymbolContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitHackyStringSymbol(@NotNull DataBinderParser.HackyStringSymbolContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterHackyStringExpr(@NotNull DataBinderParser.HackyStringExprContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitHackyStringExpr(@NotNull DataBinderParser.HackyStringExprContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterMethodCallExpr(@NotNull DataBinderParser.MethodCallExprContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitMethodCallExpr(@NotNull DataBinderParser.MethodCallExprContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterEqExpr(@NotNull DataBinderParser.EqExprContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitEqExpr(@NotNull DataBinderParser.EqExprContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterNil(@NotNull DataBinderParser.NilContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitNil(@NotNull DataBinderParser.NilContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterExprList(@NotNull DataBinderParser.ExprListContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitExprList(@NotNull DataBinderParser.ExprListContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterEveryRule(@NotNull ParserRuleContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitEveryRule(@NotNull ParserRuleContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void visitTerminal(@NotNull TerminalNode node) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void visitErrorNode(@NotNull ErrorNode node) { } +} \ No newline at end of file diff --git a/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderBaseVisitor.java b/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderBaseVisitor.java new file mode 100644 index 0000000..8355162 --- /dev/null +++ b/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderBaseVisitor.java @@ -0,0 +1,151 @@ +// Generated from DataBinder.g4 by ANTLR 4.4 +package com.android.databinding; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.misc.NotNull; +import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; + +/** + * This class provides an empty implementation of {@link DataBinderVisitor}, + * which can be extended to create a visitor which only needs to handle a subset + * of the available methods. + * + * @param The return type of the visit operation. Use {@link Void} for + * operations with no return type. + */ +public class DataBinderBaseVisitor extends AbstractParseTreeVisitor implements DataBinderVisitor { + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitSymbol(@NotNull DataBinderParser.SymbolContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitIdExpr(@NotNull DataBinderParser.IdExprContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitAtomExpr(@NotNull DataBinderParser.AtomExprContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitExpr(@NotNull DataBinderParser.ExprContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitTernaryExpr(@NotNull DataBinderParser.TernaryExprContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitGlobalMethodCallExpr(@NotNull DataBinderParser.GlobalMethodCallExprContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitInnerExpr(@NotNull DataBinderParser.InnerExprContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitField(@NotNull DataBinderParser.FieldContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitOpExpr(@NotNull DataBinderParser.OpExprContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitNilExpr(@NotNull DataBinderParser.NilExprContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitStart(@NotNull DataBinderParser.StartContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitHackyStringSymbol(@NotNull DataBinderParser.HackyStringSymbolContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitHackyStringExpr(@NotNull DataBinderParser.HackyStringExprContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitMethodCallExpr(@NotNull DataBinderParser.MethodCallExprContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitEqExpr(@NotNull DataBinderParser.EqExprContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitNil(@NotNull DataBinderParser.NilContext ctx) { return visitChildren(ctx); } + + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public Result visitExprList(@NotNull DataBinderParser.ExprListContext ctx) { return visitChildren(ctx); } +} \ No newline at end of file diff --git a/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderLexer.java b/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderLexer.java new file mode 100644 index 0000000..a0d70a8 --- /dev/null +++ b/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderLexer.java @@ -0,0 +1,130 @@ +// Generated from DataBinder.g4 by ANTLR 4.4 +package com.android.databinding; +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenStream; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.misc.*; + +public class DataBinderLexer extends Lexer { + public static final int + T__11=1, T__10=2, T__9=3, T__8=4, T__7=5, T__6=6, T__5=7, T__4=8, T__3=9, + T__2=10, T__1=11, T__0=12, Identifier=13, INT=14, BOOLEAN=15, HackyStringLiteral=16, + StringLiteral=17, CharacterLiteral=18, WS=19; + public static String[] modeNames = { + "DEFAULT_MODE" + }; + + public static final String[] tokenNames = { + "'\\u0000'", "'\\u0001'", "'\\u0002'", "'\\u0003'", "'\\u0004'", "'\\u0005'", + "'\\u0006'", "'\\u0007'", "'\b'", "'\t'", "'\n'", "'\\u000B'", "'\f'", + "'\r'", "'\\u000E'", "'\\u000F'", "'\\u0010'", "'\\u0011'", "'\\u0012'", + "'\\u0013'" + }; + public static final String[] ruleNames = { + "T__11", "T__10", "T__9", "T__8", "T__7", "T__6", "T__5", "T__4", "T__3", + "T__2", "T__1", "T__0", "Identifier", "INT", "BOOLEAN", "JavaLetter", + "JavaLetterOrDigit", "HackyStringLiteral", "StringLiteral", "CharacterLiteral", + "SingleCharacter", "StringCharacters", "StringCharacter", "WS" + }; + + + public DataBinderLexer(CharStream input) { + super(input); + _interp = new LexerATNSimulator(this,_ATN); + } + + @Override + public String getGrammarFileName() { return "DataBinder.g4"; } + + @Override + public String[] getTokenNames() { return tokenNames; } + + @Override + public String[] getRuleNames() { return ruleNames; } + + @Override + public String getSerializedATN() { return _serializedATN; } + + @Override + public String[] getModeNames() { return modeNames; } + + @Override + public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { + switch (ruleIndex) { + case 15 : return JavaLetter_sempred(_localctx, predIndex); + + case 16 : return JavaLetterOrDigit_sempred(_localctx, predIndex); + } + return true; + } + private boolean JavaLetterOrDigit_sempred(RuleContext _localctx, int predIndex) { + switch (predIndex) { + case 2: return Character.isJavaIdentifierPart(_input.LA(-1)); + + case 3: return Character.isJavaIdentifierPart(Character.toCodePoint((char)_input.LA(-2), (char)_input.LA(-1))); + } + return true; + } + private boolean JavaLetter_sempred(RuleContext _localctx, int predIndex) { + switch (predIndex) { + case 0: return Character.isJavaIdentifierStart(_input.LA(-1)); + + case 1: return Character.isJavaIdentifierStart(Character.toCodePoint((char)_input.LA(-2), (char)_input.LA(-1))); + } + return true; + } + + public static final String _serializedATN = + "\3\uaf6f\u8320\u479d\ub75c\u4880\u1605\u191c\uab37\2\25\u0096\b\1\4\2"+ + "\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4"+ + "\13\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22"+ + "\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31"+ + "\t\31\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6\3\7\3\7\3\b"+ + "\3\b\3\t\3\t\3\n\3\n\3\13\3\13\3\f\3\f\3\f\3\r\3\r\3\16\3\16\7\16R\n\16"+ + "\f\16\16\16U\13\16\3\17\6\17X\n\17\r\17\16\17Y\3\20\3\20\3\20\3\20\3\20"+ + "\3\20\3\20\3\20\3\20\5\20e\n\20\3\21\3\21\3\21\3\21\3\21\3\21\5\21m\n"+ + "\21\3\22\3\22\3\22\3\22\3\22\3\22\5\22u\n\22\3\23\3\23\5\23y\n\23\3\23"+ + "\3\23\3\24\3\24\5\24\177\n\24\3\24\3\24\3\25\3\25\3\25\3\25\3\26\3\26"+ + "\3\27\6\27\u008a\n\27\r\27\16\27\u008b\3\30\3\30\3\31\6\31\u0091\n\31"+ + "\r\31\16\31\u0092\3\31\3\31\2\2\2\32\3\2\3\5\2\4\7\2\5\t\2\6\13\2\7\r"+ + "\2\b\17\2\t\21\2\n\23\2\13\25\2\f\27\2\r\31\2\16\33\2\17\35\2\20\37\2"+ + "\21!\2\2#\2\2%\2\22\'\2\23)\2\24+\2\2-\2\2/\2\2\61\2\25\3\2\n\6\2&&C\\"+ + "aac|\4\2\2\u0101\ud802\udc01\3\2\ud802\udc01\3\2\udc02\ue001\7\2&&\62"+ + ";C\\aac|\4\2))^^\4\2$$^^\5\2\13\f\17\17\"\"\u009b\2\3\3\2\2\2\2\5\3\2"+ + "\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21"+ + "\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2"+ + "\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2\61"+ + "\3\2\2\2\3\63\3\2\2\2\58\3\2\2\2\7:\3\2\2\2\t<\3\2\2\2\13>\3\2\2\2\r@"+ + "\3\2\2\2\17B\3\2\2\2\21D\3\2\2\2\23F\3\2\2\2\25H\3\2\2\2\27J\3\2\2\2\31"+ + "M\3\2\2\2\33O\3\2\2\2\35W\3\2\2\2\37d\3\2\2\2!l\3\2\2\2#t\3\2\2\2%v\3"+ + "\2\2\2\'|\3\2\2\2)\u0082\3\2\2\2+\u0086\3\2\2\2-\u0089\3\2\2\2/\u008d"+ + "\3\2\2\2\61\u0090\3\2\2\2\63\64\7p\2\2\64\65\7w\2\2\65\66\7n\2\2\66\67"+ + "\7n\2\2\67\4\3\2\2\289\7+\2\29\6\3\2\2\2:;\7\60\2\2;\b\3\2\2\2<=\7.\2"+ + "\2=\n\3\2\2\2>?\7-\2\2?\f\3\2\2\2@A\7,\2\2A\16\3\2\2\2BC\7/\2\2C\20\3"+ + "\2\2\2DE\7*\2\2E\22\3\2\2\2FG\7<\2\2G\24\3\2\2\2HI\7\61\2\2I\26\3\2\2"+ + "\2JK\7?\2\2KL\7?\2\2L\30\3\2\2\2MN\7A\2\2N\32\3\2\2\2OS\5!\21\2PR\5#\22"+ + "\2QP\3\2\2\2RU\3\2\2\2SQ\3\2\2\2ST\3\2\2\2T\34\3\2\2\2US\3\2\2\2VX\4\62"+ + ";\2WV\3\2\2\2XY\3\2\2\2YW\3\2\2\2YZ\3\2\2\2Z\36\3\2\2\2[\\\7v\2\2\\]\7"+ + "t\2\2]^\7w\2\2^e\7g\2\2_`\7h\2\2`a\7c\2\2ab\7n\2\2bc\7u\2\2ce\7g\2\2d"+ + "[\3\2\2\2d_\3\2\2\2e \3\2\2\2fm\t\2\2\2gh\n\3\2\2hm\6\21\2\2ij\t\4\2\2"+ + "jk\t\5\2\2km\6\21\3\2lf\3\2\2\2lg\3\2\2\2li\3\2\2\2m\"\3\2\2\2nu\t\6\2"+ + "\2op\n\3\2\2pu\6\22\4\2qr\t\4\2\2rs\t\5\2\2su\6\22\5\2tn\3\2\2\2to\3\2"+ + "\2\2tq\3\2\2\2u$\3\2\2\2vx\7b\2\2wy\5-\27\2xw\3\2\2\2xy\3\2\2\2yz\3\2"+ + "\2\2z{\7b\2\2{&\3\2\2\2|~\7$\2\2}\177\5-\27\2~}\3\2\2\2~\177\3\2\2\2\177"+ + "\u0080\3\2\2\2\u0080\u0081\7$\2\2\u0081(\3\2\2\2\u0082\u0083\7)\2\2\u0083"+ + "\u0084\5+\26\2\u0084\u0085\7)\2\2\u0085*\3\2\2\2\u0086\u0087\n\7\2\2\u0087"+ + ",\3\2\2\2\u0088\u008a\5/\30\2\u0089\u0088\3\2\2\2\u008a\u008b\3\2\2\2"+ + "\u008b\u0089\3\2\2\2\u008b\u008c\3\2\2\2\u008c.\3\2\2\2\u008d\u008e\n"+ + "\b\2\2\u008e\60\3\2\2\2\u008f\u0091\t\t\2\2\u0090\u008f\3\2\2\2\u0091"+ + "\u0092\3\2\2\2\u0092\u0090\3\2\2\2\u0092\u0093\3\2\2\2\u0093\u0094\3\2"+ + "\2\2\u0094\u0095\b\31\2\2\u0095\62\3\2\2\2\f\2SYdltx~\u008b\u0092\3\b"+ + "\2\2"; + public static final ATN _ATN = + new ATNDeserializer().deserialize(_serializedATN.toCharArray()); + static { + } +} \ No newline at end of file diff --git a/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderLexer.tokens b/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderLexer.tokens new file mode 100644 index 0000000..3696716 --- /dev/null +++ b/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderLexer.tokens @@ -0,0 +1,31 @@ +StringLiteral=17 +HackyStringLiteral=16 +WS=19 +BOOLEAN=15 +T__11=1 +CharacterLiteral=18 +T__1=11 +T__0=12 +T__10=2 +T__3=9 +T__2=10 +INT=14 +T__9=3 +T__8=4 +Identifier=13 +T__7=5 +T__6=6 +T__5=7 +T__4=8 +'?'=12 +'=='=11 +'/'=10 +':'=9 +'('=8 +'-'=7 +'*'=6 +'+'=5 +','=4 +'.'=3 +')'=2 +'null'=1 diff --git a/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderListener.java b/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderListener.java new file mode 100644 index 0000000..12adab7 --- /dev/null +++ b/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderListener.java @@ -0,0 +1,218 @@ +// Generated from DataBinder.g4 by ANTLR 4.4 +package com.android.databinding; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.misc.NotNull; +import org.antlr.v4.runtime.tree.ParseTreeListener; + +/** + * This interface defines a complete listener for a parse tree produced by + * {@link DataBinderParser}. + */ +public interface DataBinderListener extends ParseTreeListener { + /** + * Enter a parse tree produced by {@link DataBinderParser#symbol}. + * @param ctx the parse tree + */ + void enterSymbol(@NotNull DataBinderParser.SymbolContext ctx); + /** + * Exit a parse tree produced by {@link DataBinderParser#symbol}. + * @param ctx the parse tree + */ + void exitSymbol(@NotNull DataBinderParser.SymbolContext ctx); + + /** + * Enter a parse tree produced by the {@code idExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void enterIdExpr(@NotNull DataBinderParser.IdExprContext ctx); + /** + * Exit a parse tree produced by the {@code idExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void exitIdExpr(@NotNull DataBinderParser.IdExprContext ctx); + + /** + * Enter a parse tree produced by the {@code atomExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void enterAtomExpr(@NotNull DataBinderParser.AtomExprContext ctx); + /** + * Exit a parse tree produced by the {@code atomExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void exitAtomExpr(@NotNull DataBinderParser.AtomExprContext ctx); + + /** + * Enter a parse tree produced by {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void enterExpr(@NotNull DataBinderParser.ExprContext ctx); + /** + * Exit a parse tree produced by {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void exitExpr(@NotNull DataBinderParser.ExprContext ctx); + + /** + * Enter a parse tree produced by the {@code ternaryExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void enterTernaryExpr(@NotNull DataBinderParser.TernaryExprContext ctx); + /** + * Exit a parse tree produced by the {@code ternaryExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void exitTernaryExpr(@NotNull DataBinderParser.TernaryExprContext ctx); + + /** + * Enter a parse tree produced by the {@code globalMethodCallExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void enterGlobalMethodCallExpr(@NotNull DataBinderParser.GlobalMethodCallExprContext ctx); + /** + * Exit a parse tree produced by the {@code globalMethodCallExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void exitGlobalMethodCallExpr(@NotNull DataBinderParser.GlobalMethodCallExprContext ctx); + + /** + * Enter a parse tree produced by the {@code innerExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void enterInnerExpr(@NotNull DataBinderParser.InnerExprContext ctx); + /** + * Exit a parse tree produced by the {@code innerExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void exitInnerExpr(@NotNull DataBinderParser.InnerExprContext ctx); + + /** + * Enter a parse tree produced by {@link DataBinderParser#field}. + * @param ctx the parse tree + */ + void enterField(@NotNull DataBinderParser.FieldContext ctx); + /** + * Exit a parse tree produced by {@link DataBinderParser#field}. + * @param ctx the parse tree + */ + void exitField(@NotNull DataBinderParser.FieldContext ctx); + + /** + * Enter a parse tree produced by the {@code opExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void enterOpExpr(@NotNull DataBinderParser.OpExprContext ctx); + /** + * Exit a parse tree produced by the {@code opExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void exitOpExpr(@NotNull DataBinderParser.OpExprContext ctx); + + /** + * Enter a parse tree produced by the {@code nilExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void enterNilExpr(@NotNull DataBinderParser.NilExprContext ctx); + /** + * Exit a parse tree produced by the {@code nilExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void exitNilExpr(@NotNull DataBinderParser.NilExprContext ctx); + + /** + * Enter a parse tree produced by {@link DataBinderParser#start}. + * @param ctx the parse tree + */ + void enterStart(@NotNull DataBinderParser.StartContext ctx); + /** + * Exit a parse tree produced by {@link DataBinderParser#start}. + * @param ctx the parse tree + */ + void exitStart(@NotNull DataBinderParser.StartContext ctx); + + /** + * Enter a parse tree produced by {@link DataBinderParser#hackyStringSymbol}. + * @param ctx the parse tree + */ + void enterHackyStringSymbol(@NotNull DataBinderParser.HackyStringSymbolContext ctx); + /** + * Exit a parse tree produced by {@link DataBinderParser#hackyStringSymbol}. + * @param ctx the parse tree + */ + void exitHackyStringSymbol(@NotNull DataBinderParser.HackyStringSymbolContext ctx); + + /** + * Enter a parse tree produced by the {@code hackyStringExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void enterHackyStringExpr(@NotNull DataBinderParser.HackyStringExprContext ctx); + /** + * Exit a parse tree produced by the {@code hackyStringExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void exitHackyStringExpr(@NotNull DataBinderParser.HackyStringExprContext ctx); + + /** + * Enter a parse tree produced by the {@code methodCallExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void enterMethodCallExpr(@NotNull DataBinderParser.MethodCallExprContext ctx); + /** + * Exit a parse tree produced by the {@code methodCallExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void exitMethodCallExpr(@NotNull DataBinderParser.MethodCallExprContext ctx); + + /** + * Enter a parse tree produced by the {@code eqExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void enterEqExpr(@NotNull DataBinderParser.EqExprContext ctx); + /** + * Exit a parse tree produced by the {@code eqExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + */ + void exitEqExpr(@NotNull DataBinderParser.EqExprContext ctx); + + /** + * Enter a parse tree produced by {@link DataBinderParser#nil}. + * @param ctx the parse tree + */ + void enterNil(@NotNull DataBinderParser.NilContext ctx); + /** + * Exit a parse tree produced by {@link DataBinderParser#nil}. + * @param ctx the parse tree + */ + void exitNil(@NotNull DataBinderParser.NilContext ctx); + + /** + * Enter a parse tree produced by {@link DataBinderParser#exprList}. + * @param ctx the parse tree + */ + void enterExprList(@NotNull DataBinderParser.ExprListContext ctx); + /** + * Exit a parse tree produced by {@link DataBinderParser#exprList}. + * @param ctx the parse tree + */ + void exitExprList(@NotNull DataBinderParser.ExprListContext ctx); +} \ No newline at end of file diff --git a/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderParser.java b/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderParser.java new file mode 100644 index 0000000..a4d306e --- /dev/null +++ b/tools/data-binding/grammerBuilder/src/main/java-gen/com/android/databinding/DataBinderParser.java @@ -0,0 +1,829 @@ +// Generated from DataBinder.g4 by ANTLR 4.4 +package com.android.databinding; +import org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.misc.*; +import org.antlr.v4.runtime.tree.*; +import java.util.List; +import java.util.Iterator; +import java.util.ArrayList; + +public class DataBinderParser extends Parser { + public static final int + T__11=1, T__10=2, T__9=3, T__8=4, T__7=5, T__6=6, T__5=7, T__4=8, T__3=9, + T__2=10, T__1=11, T__0=12, Identifier=13, INT=14, BOOLEAN=15, HackyStringLiteral=16, + StringLiteral=17, CharacterLiteral=18, WS=19; + public static final String[] tokenNames = { + "", "'null'", "')'", "'.'", "','", "'+'", "'*'", "'-'", "'('", + "':'", "'/'", "'=='", "'?'", "Identifier", "INT", "BOOLEAN", "HackyStringLiteral", + "StringLiteral", "CharacterLiteral", "WS" + }; + public static final int + RULE_start = 0, RULE_expr = 1, RULE_exprList = 2, RULE_field = 3, RULE_hackyStringSymbol = 4, + RULE_symbol = 5, RULE_nil = 6; + public static final String[] ruleNames = { + "start", "expr", "exprList", "field", "hackyStringSymbol", "symbol", "nil" + }; + + @Override + public String getGrammarFileName() { return "DataBinder.g4"; } + + @Override + public String[] getTokenNames() { return tokenNames; } + + @Override + public String[] getRuleNames() { return ruleNames; } + + @Override + public String getSerializedATN() { return _serializedATN; } + + public DataBinderParser(TokenStream input) { + super(input); + _interp = new ParserATNSimulator(this,_ATN); + } + public static class StartContext extends ParserRuleContext { + public ExprContext expr() { + return getRuleContext(ExprContext.class,0); + } + public StartContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_start; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterStart(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitStart(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitStart(this); + else return visitor.visitChildren(this); + } + } + + @RuleVersion(0) + public final StartContext start() throws RecognitionException { + StartContext _localctx = new StartContext(_ctx, getState()); + enterRule(_localctx, 0, RULE_start); + try { + enterOuterAlt(_localctx, 1); + { + setState(14); expr(0); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class ExprContext extends ParserRuleContext { + public ExprContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_expr; } + + public ExprContext() { } + public void copyFrom(ExprContext ctx) { + super.copyFrom(ctx); + } + } + public static class OpExprContext extends ExprContext { + public ExprContext left; + public Token op; + public ExprContext right; + public List expr() { + return getRuleContexts(ExprContext.class); + } + public ExprContext expr(int i) { + return getRuleContext(ExprContext.class,i); + } + public OpExprContext(ExprContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterOpExpr(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitOpExpr(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitOpExpr(this); + else return visitor.visitChildren(this); + } + } + public static class NilExprContext extends ExprContext { + public NilContext nil() { + return getRuleContext(NilContext.class,0); + } + public NilExprContext(ExprContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterNilExpr(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitNilExpr(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitNilExpr(this); + else return visitor.visitChildren(this); + } + } + public static class IdExprContext extends ExprContext { + public FieldContext field() { + return getRuleContext(FieldContext.class,0); + } + public IdExprContext(ExprContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterIdExpr(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitIdExpr(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitIdExpr(this); + else return visitor.visitChildren(this); + } + } + public static class AtomExprContext extends ExprContext { + public SymbolContext atom; + public SymbolContext symbol() { + return getRuleContext(SymbolContext.class,0); + } + public AtomExprContext(ExprContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterAtomExpr(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitAtomExpr(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitAtomExpr(this); + else return visitor.visitChildren(this); + } + } + public static class HackyStringExprContext extends ExprContext { + public HackyStringSymbolContext atomString; + public HackyStringSymbolContext hackyStringSymbol() { + return getRuleContext(HackyStringSymbolContext.class,0); + } + public HackyStringExprContext(ExprContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterHackyStringExpr(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitHackyStringExpr(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitHackyStringExpr(this); + else return visitor.visitChildren(this); + } + } + public static class TernaryExprContext extends ExprContext { + public ExprContext pred; + public ExprContext t; + public ExprContext f; + public List expr() { + return getRuleContexts(ExprContext.class); + } + public ExprContext expr(int i) { + return getRuleContext(ExprContext.class,i); + } + public TernaryExprContext(ExprContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterTernaryExpr(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitTernaryExpr(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitTernaryExpr(this); + else return visitor.visitChildren(this); + } + } + public static class InnerExprContext extends ExprContext { + public ExprContext inner; + public ExprContext expr() { + return getRuleContext(ExprContext.class,0); + } + public InnerExprContext(ExprContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterInnerExpr(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitInnerExpr(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitInnerExpr(this); + else return visitor.visitChildren(this); + } + } + public static class GlobalMethodCallExprContext extends ExprContext { + public Token methodName; + public ExprListContext arguments; + public ExprListContext exprList() { + return getRuleContext(ExprListContext.class,0); + } + public TerminalNode Identifier() { return getToken(DataBinderParser.Identifier, 0); } + public GlobalMethodCallExprContext(ExprContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterGlobalMethodCallExpr(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitGlobalMethodCallExpr(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitGlobalMethodCallExpr(this); + else return visitor.visitChildren(this); + } + } + public static class MethodCallExprContext extends ExprContext { + public ExprContext ownerObj; + public Token methodName; + public ExprListContext arguments; + public ExprListContext exprList() { + return getRuleContext(ExprListContext.class,0); + } + public ExprContext expr() { + return getRuleContext(ExprContext.class,0); + } + public TerminalNode Identifier() { return getToken(DataBinderParser.Identifier, 0); } + public MethodCallExprContext(ExprContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterMethodCallExpr(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitMethodCallExpr(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitMethodCallExpr(this); + else return visitor.visitChildren(this); + } + } + public static class EqExprContext extends ExprContext { + public ExprContext left; + public ExprContext right; + public List expr() { + return getRuleContexts(ExprContext.class); + } + public ExprContext expr(int i) { + return getRuleContext(ExprContext.class,i); + } + public EqExprContext(ExprContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterEqExpr(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitEqExpr(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitEqExpr(this); + else return visitor.visitChildren(this); + } + } + + @RuleVersion(0) + public final ExprContext expr() throws RecognitionException { + return expr(0); + } + + private ExprContext expr(int _p) throws RecognitionException { + ParserRuleContext _parentctx = _ctx; + int _parentState = getState(); + ExprContext _localctx = new ExprContext(_ctx, _parentState); + ExprContext _prevctx = _localctx; + int _startState = 2; + enterRecursionRule(_localctx, 2, RULE_expr, _p); + int _la; + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(31); + switch ( getInterpreter().adaptivePredict(_input,1,_ctx) ) { + case 1: + { + _localctx = new NilExprContext(_localctx); + _ctx = _localctx; + _prevctx = _localctx; + + setState(17); nil(); + } + break; + + case 2: + { + _localctx = new InnerExprContext(_localctx); + _ctx = _localctx; + _prevctx = _localctx; + setState(18); match(T__4); + setState(19); ((InnerExprContext)_localctx).inner = expr(0); + setState(20); match(T__10); + } + break; + + case 3: + { + _localctx = new GlobalMethodCallExprContext(_localctx); + _ctx = _localctx; + _prevctx = _localctx; + setState(22); ((GlobalMethodCallExprContext)_localctx).methodName = match(Identifier); + setState(23); match(T__4); + setState(25); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__11) | (1L << T__4) | (1L << Identifier) | (1L << INT) | (1L << BOOLEAN) | (1L << HackyStringLiteral) | (1L << StringLiteral) | (1L << CharacterLiteral))) != 0)) { + { + setState(24); ((GlobalMethodCallExprContext)_localctx).arguments = exprList(); + } + } + + setState(27); match(T__10); + } + break; + + case 4: + { + _localctx = new HackyStringExprContext(_localctx); + _ctx = _localctx; + _prevctx = _localctx; + setState(28); ((HackyStringExprContext)_localctx).atomString = hackyStringSymbol(); + } + break; + + case 5: + { + _localctx = new AtomExprContext(_localctx); + _ctx = _localctx; + _prevctx = _localctx; + setState(29); ((AtomExprContext)_localctx).atom = symbol(); + } + break; + + case 6: + { + _localctx = new IdExprContext(_localctx); + _ctx = _localctx; + _prevctx = _localctx; + setState(30); field(); + } + break; + } + _ctx.stop = _input.LT(-1); + setState(58); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,4,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + if ( _parseListeners!=null ) triggerExitRuleEvent(); + _prevctx = _localctx; + { + setState(56); + switch ( getInterpreter().adaptivePredict(_input,3,_ctx) ) { + case 1: + { + _localctx = new OpExprContext(new ExprContext(_parentctx, _parentState)); + ((OpExprContext)_localctx).left = _prevctx; + pushNewRecursionContext(_localctx, _startState, RULE_expr); + setState(33); + if (!(precpred(_ctx, 4))) throw new FailedPredicateException(this, "precpred(_ctx, 4)"); + setState(34); + ((OpExprContext)_localctx).op = _input.LT(1); + _la = _input.LA(1); + if ( !(_la==T__6 || _la==T__2) ) { + ((OpExprContext)_localctx).op = _errHandler.recoverInline(this); + } + consume(); + setState(35); ((OpExprContext)_localctx).right = expr(5); + } + break; + + case 2: + { + _localctx = new OpExprContext(new ExprContext(_parentctx, _parentState)); + ((OpExprContext)_localctx).left = _prevctx; + pushNewRecursionContext(_localctx, _startState, RULE_expr); + setState(36); + if (!(precpred(_ctx, 3))) throw new FailedPredicateException(this, "precpred(_ctx, 3)"); + setState(37); + ((OpExprContext)_localctx).op = _input.LT(1); + _la = _input.LA(1); + if ( !(_la==T__7 || _la==T__5) ) { + ((OpExprContext)_localctx).op = _errHandler.recoverInline(this); + } + consume(); + setState(38); ((OpExprContext)_localctx).right = expr(4); + } + break; + + case 3: + { + _localctx = new EqExprContext(new ExprContext(_parentctx, _parentState)); + ((EqExprContext)_localctx).left = _prevctx; + pushNewRecursionContext(_localctx, _startState, RULE_expr); + setState(39); + if (!(precpred(_ctx, 2))) throw new FailedPredicateException(this, "precpred(_ctx, 2)"); + setState(40); match(T__1); + setState(41); ((EqExprContext)_localctx).right = expr(3); + } + break; + + case 4: + { + _localctx = new TernaryExprContext(new ExprContext(_parentctx, _parentState)); + ((TernaryExprContext)_localctx).pred = _prevctx; + pushNewRecursionContext(_localctx, _startState, RULE_expr); + setState(42); + if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)"); + setState(43); match(T__0); + setState(44); ((TernaryExprContext)_localctx).t = expr(0); + setState(45); match(T__3); + setState(46); ((TernaryExprContext)_localctx).f = expr(2); + } + break; + + case 5: + { + _localctx = new MethodCallExprContext(new ExprContext(_parentctx, _parentState)); + ((MethodCallExprContext)_localctx).ownerObj = _prevctx; + pushNewRecursionContext(_localctx, _startState, RULE_expr); + setState(48); + if (!(precpred(_ctx, 9))) throw new FailedPredicateException(this, "precpred(_ctx, 9)"); + setState(49); match(T__9); + setState(50); ((MethodCallExprContext)_localctx).methodName = match(Identifier); + setState(51); match(T__4); + setState(53); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__11) | (1L << T__4) | (1L << Identifier) | (1L << INT) | (1L << BOOLEAN) | (1L << HackyStringLiteral) | (1L << StringLiteral) | (1L << CharacterLiteral))) != 0)) { + { + setState(52); ((MethodCallExprContext)_localctx).arguments = exprList(); + } + } + + setState(55); match(T__10); + } + break; + } + } + } + setState(60); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,4,_ctx); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + unrollRecursionContexts(_parentctx); + } + return _localctx; + } + + public static class ExprListContext extends ParserRuleContext { + public List expr() { + return getRuleContexts(ExprContext.class); + } + public ExprContext expr(int i) { + return getRuleContext(ExprContext.class,i); + } + public ExprListContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_exprList; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterExprList(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitExprList(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitExprList(this); + else return visitor.visitChildren(this); + } + } + + @RuleVersion(0) + public final ExprListContext exprList() throws RecognitionException { + ExprListContext _localctx = new ExprListContext(_ctx, getState()); + enterRule(_localctx, 4, RULE_exprList); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(61); expr(0); + setState(66); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==T__8) { + { + { + setState(62); match(T__8); + setState(63); expr(0); + } + } + setState(68); + _errHandler.sync(this); + _la = _input.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class FieldContext extends ParserRuleContext { + public Token name; + public TerminalNode Identifier(int i) { + return getToken(DataBinderParser.Identifier, i); + } + public List Identifier() { return getTokens(DataBinderParser.Identifier); } + public FieldContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_field; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterField(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitField(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitField(this); + else return visitor.visitChildren(this); + } + } + + @RuleVersion(0) + public final FieldContext field() throws RecognitionException { + FieldContext _localctx = new FieldContext(_ctx, getState()); + enterRule(_localctx, 6, RULE_field); + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(69); _localctx.name = match(Identifier); + setState(74); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,6,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(70); match(T__9); + setState(71); match(Identifier); + } + } + } + setState(76); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,6,_ctx); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class HackyStringSymbolContext extends ParserRuleContext { + public TerminalNode HackyStringLiteral() { return getToken(DataBinderParser.HackyStringLiteral, 0); } + public HackyStringSymbolContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_hackyStringSymbol; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterHackyStringSymbol(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitHackyStringSymbol(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitHackyStringSymbol(this); + else return visitor.visitChildren(this); + } + } + + @RuleVersion(0) + public final HackyStringSymbolContext hackyStringSymbol() throws RecognitionException { + HackyStringSymbolContext _localctx = new HackyStringSymbolContext(_ctx, getState()); + enterRule(_localctx, 8, RULE_hackyStringSymbol); + try { + enterOuterAlt(_localctx, 1); + { + setState(77); match(HackyStringLiteral); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class SymbolContext extends ParserRuleContext { + public TerminalNode BOOLEAN() { return getToken(DataBinderParser.BOOLEAN, 0); } + public TerminalNode INT() { return getToken(DataBinderParser.INT, 0); } + public TerminalNode CharacterLiteral() { return getToken(DataBinderParser.CharacterLiteral, 0); } + public TerminalNode StringLiteral() { return getToken(DataBinderParser.StringLiteral, 0); } + public SymbolContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_symbol; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterSymbol(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitSymbol(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitSymbol(this); + else return visitor.visitChildren(this); + } + } + + @RuleVersion(0) + public final SymbolContext symbol() throws RecognitionException { + SymbolContext _localctx = new SymbolContext(_ctx, getState()); + enterRule(_localctx, 10, RULE_symbol); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(79); + _la = _input.LA(1); + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << INT) | (1L << BOOLEAN) | (1L << StringLiteral) | (1L << CharacterLiteral))) != 0)) ) { + _errHandler.recoverInline(this); + } + consume(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class NilContext extends ParserRuleContext { + public NilContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_nil; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).enterNil(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof DataBinderListener ) ((DataBinderListener)listener).exitNil(this); + } + @Override + public Result accept(ParseTreeVisitor visitor) { + if ( visitor instanceof DataBinderVisitor ) return ((DataBinderVisitor)visitor).visitNil(this); + else return visitor.visitChildren(this); + } + } + + @RuleVersion(0) + public final NilContext nil() throws RecognitionException { + NilContext _localctx = new NilContext(_ctx, getState()); + enterRule(_localctx, 12, RULE_nil); + try { + enterOuterAlt(_localctx, 1); + { + setState(81); match(T__11); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { + switch (ruleIndex) { + case 1: return expr_sempred((ExprContext)_localctx, predIndex); + } + return true; + } + private boolean expr_sempred(ExprContext _localctx, int predIndex) { + switch (predIndex) { + case 0: return precpred(_ctx, 4); + + case 1: return precpred(_ctx, 3); + + case 2: return precpred(_ctx, 2); + + case 3: return precpred(_ctx, 1); + + case 4: return precpred(_ctx, 9); + } + return true; + } + + public static final String _serializedATN = + "\3\uaf6f\u8320\u479d\ub75c\u4880\u1605\u191c\uab37\3\25V\4\2\t\2\4\3\t"+ + "\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\3\2\3\2\3\3\3\3\3\3\3\3\3\3"+ + "\3\3\3\3\3\3\3\3\5\3\34\n\3\3\3\3\3\3\3\3\3\5\3\"\n\3\3\3\3\3\3\3\3\3"+ + "\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\5\38"+ + "\n\3\3\3\7\3;\n\3\f\3\16\3>\13\3\3\4\3\4\3\4\7\4C\n\4\f\4\16\4F\13\4\3"+ + "\5\3\5\3\5\7\5K\n\5\f\5\16\5N\13\5\3\6\3\6\3\7\3\7\3\b\3\b\3\b\2\2\3\4"+ + "\t\2\2\4\2\6\2\b\2\n\2\f\2\16\2\2\5\4\2\b\b\f\f\4\2\7\7\t\t\4\2\20\21"+ + "\23\24\\\2\20\3\2\2\2\4!\3\2\2\2\6?\3\2\2\2\bG\3\2\2\2\nO\3\2\2\2\fQ\3"+ + "\2\2\2\16S\3\2\2\2\20\21\5\4\3\2\21\3\3\2\2\2\22\23\b\3\1\2\23\"\5\16"+ + "\b\2\24\25\7\n\2\2\25\26\5\4\3\2\26\27\7\4\2\2\27\"\3\2\2\2\30\31\7\17"+ + "\2\2\31\33\7\n\2\2\32\34\5\6\4\2\33\32\3\2\2\2\33\34\3\2\2\2\34\35\3\2"+ + "\2\2\35\"\7\4\2\2\36\"\5\n\6\2\37\"\5\f\7\2 \"\5\b\5\2!\22\3\2\2\2!\24"+ + "\3\2\2\2!\30\3\2\2\2!\36\3\2\2\2!\37\3\2\2\2! \3\2\2\2\"<\3\2\2\2#$\f"+ + "\6\2\2$%\t\2\2\2%;\5\4\3\7&\'\f\5\2\2\'(\t\3\2\2(;\5\4\3\6)*\f\4\2\2*"+ + "+\7\r\2\2+;\5\4\3\5,-\f\3\2\2-.\7\16\2\2./\5\4\3\2/\60\7\13\2\2\60\61"+ + "\5\4\3\4\61;\3\2\2\2\62\63\f\13\2\2\63\64\7\5\2\2\64\65\7\17\2\2\65\67"+ + "\7\n\2\2\668\5\6\4\2\67\66\3\2\2\2\678\3\2\2\289\3\2\2\29;\7\4\2\2:#\3"+ + "\2\2\2:&\3\2\2\2:)\3\2\2\2:,\3\2\2\2:\62\3\2\2\2;>\3\2\2\2<:\3\2\2\2<"+ + "=\3\2\2\2=\5\3\2\2\2><\3\2\2\2?D\5\4\3\2@A\7\6\2\2AC\5\4\3\2B@\3\2\2\2"+ + "CF\3\2\2\2DB\3\2\2\2DE\3\2\2\2E\7\3\2\2\2FD\3\2\2\2GL\7\17\2\2HI\7\5\2"+ + "\2IK\7\17\2\2JH\3\2\2\2KN\3\2\2\2LJ\3\2\2\2LM\3\2\2\2M\t\3\2\2\2NL\3\2"+ + "\2\2OP\7\22\2\2P\13\3\2\2\2QR\t\4\2\2R\r\3\2\2\2ST\7\3\2\2T\17\3\2\2\2"+ + "\t\33!\67: The return type of the visit operation. Use {@link Void} for + * operations with no return type. + */ +public interface DataBinderVisitor extends ParseTreeVisitor { + /** + * Visit a parse tree produced by {@link DataBinderParser#symbol}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitSymbol(@NotNull DataBinderParser.SymbolContext ctx); + + /** + * Visit a parse tree produced by the {@code idExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitIdExpr(@NotNull DataBinderParser.IdExprContext ctx); + + /** + * Visit a parse tree produced by the {@code atomExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitAtomExpr(@NotNull DataBinderParser.AtomExprContext ctx); + + /** + * Visit a parse tree produced by {@link DataBinderParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitExpr(@NotNull DataBinderParser.ExprContext ctx); + + /** + * Visit a parse tree produced by the {@code ternaryExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitTernaryExpr(@NotNull DataBinderParser.TernaryExprContext ctx); + + /** + * Visit a parse tree produced by the {@code globalMethodCallExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitGlobalMethodCallExpr(@NotNull DataBinderParser.GlobalMethodCallExprContext ctx); + + /** + * Visit a parse tree produced by the {@code innerExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitInnerExpr(@NotNull DataBinderParser.InnerExprContext ctx); + + /** + * Visit a parse tree produced by {@link DataBinderParser#field}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitField(@NotNull DataBinderParser.FieldContext ctx); + + /** + * Visit a parse tree produced by the {@code opExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitOpExpr(@NotNull DataBinderParser.OpExprContext ctx); + + /** + * Visit a parse tree produced by the {@code nilExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitNilExpr(@NotNull DataBinderParser.NilExprContext ctx); + + /** + * Visit a parse tree produced by {@link DataBinderParser#start}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitStart(@NotNull DataBinderParser.StartContext ctx); + + /** + * Visit a parse tree produced by {@link DataBinderParser#hackyStringSymbol}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitHackyStringSymbol(@NotNull DataBinderParser.HackyStringSymbolContext ctx); + + /** + * Visit a parse tree produced by the {@code hackyStringExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitHackyStringExpr(@NotNull DataBinderParser.HackyStringExprContext ctx); + + /** + * Visit a parse tree produced by the {@code methodCallExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitMethodCallExpr(@NotNull DataBinderParser.MethodCallExprContext ctx); + + /** + * Visit a parse tree produced by the {@code eqExpr} + * labeled alternative in {@link DataBinderParser#expr}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitEqExpr(@NotNull DataBinderParser.EqExprContext ctx); + + /** + * Visit a parse tree produced by {@link DataBinderParser#nil}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitNil(@NotNull DataBinderParser.NilContext ctx); + + /** + * Visit a parse tree produced by {@link DataBinderParser#exprList}. + * @param ctx the parse tree + * @return the visitor result + */ + Result visitExprList(@NotNull DataBinderParser.ExprListContext ctx); +} \ No newline at end of file diff --git a/tools/data-binding/grammerBuilder/src/main/java/com/android/databinder/parser/Main.java b/tools/data-binding/grammerBuilder/src/main/java/com/android/databinder/parser/Main.java new file mode 100644 index 0000000..861289b --- /dev/null +++ b/tools/data-binding/grammerBuilder/src/main/java/com/android/databinder/parser/Main.java @@ -0,0 +1,24 @@ +package com.android.databinder.parser; + +import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.tree.ParseTreeWalker; + +/** + * Created by yboyar on 11/15/14. + */ +public class Main { + static String input = "`name` + last_name"; + static class Field { + String fieldName; + } + public static void main(String[] args) { + // ANTLRInputStream inputStream = new ANTLRInputStream(input); +// DataBinderLexer lexer = new DataBinderLexer(inputStream); +// CommonTokenStream tokenStream = new CommonTokenStream(lexer); +// DataBinderParser parser = new DataBinderParser(tokenStream); +// ParseTreeWalker walker = new ParseTreeWalker(); +// System.out.println(parser.expr().toStringTree(parser)); + + } +} diff --git a/tools/data-binding/library/build.gradle b/tools/data-binding/library/build.gradle new file mode 100644 index 0000000..a5b9cec --- /dev/null +++ b/tools/data-binding/library/build.gradle @@ -0,0 +1,69 @@ + +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + mavenLocal() + jcenter() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:0.14.2' + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +apply plugin: 'com.android.library' +apply plugin: 'maven' +android { + compileSdkVersion 21 + buildToolsVersion "21.1" + + defaultConfig { + applicationId "com.android.databinding.library" + minSdkVersion 7 + targetSdkVersion 21 + versionCode 1 + versionName "1.0" + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + buildTypes { + release { + runProguard false + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) +} +//create jar tasks +android.libraryVariants.all { variant -> + def name = variant.buildType.name + + if (name.equals("debug")) { + return; // Skip debug builds. + } + def suffix = name.capitalize() + +// def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) { +// classifier = 'sources' +// from android.sourceSets.main.java +// } +// +// artifacts.add('archives', sourcesJarTask); +} +uploadArchives { + repositories { + mavenDeployer { + repository(url: mavenLocal().url) + pom.version = '0.1-SNAPSHOT' + pom.artifactId = 'library' + pom.groupId='com.android.databinding' + } + } +} diff --git a/tools/data-binding/library/src/main/AndroidManifest.xml b/tools/data-binding/library/src/main/AndroidManifest.xml new file mode 100644 index 0000000..77d734f --- /dev/null +++ b/tools/data-binding/library/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/BaseObservable.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/BaseObservable.java new file mode 100644 index 0000000..1b4b6a7 --- /dev/null +++ b/tools/data-binding/library/src/main/java/com/android/databinding/library/BaseObservable.java @@ -0,0 +1,32 @@ +package com.android.databinding.library; + +import java.util.concurrent.CopyOnWriteArraySet; + +/** + * Created by yboyar on 11/9/14. + */ +public class BaseObservable implements Observable { + final ObservableHelper mHelper; + + public BaseObservable() { + mHelper = new ObservableHelper(this); + } + + @Override + public void register(ObservableListener listener) { + mHelper.register(listener); + } + + @Override + public void unRegister(ObservableListener listener) { + mHelper.unRegister(listener); + } + + public void fireChange() { + mHelper.fireChange(); + } + public void fireChange(String fieldName) { + mHelper.fireChange(fieldName); + } + public void fireChange(int fieldId) {mHelper.fireChange(fieldId);} +} diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/DataBinder.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/DataBinder.java new file mode 100644 index 0000000..3241cd8 --- /dev/null +++ b/tools/data-binding/library/src/main/java/com/android/databinding/library/DataBinder.java @@ -0,0 +1,106 @@ +package com.android.databinding.library; + +import android.content.Context; +import android.util.Log; +import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import java.lang.ref.WeakReference; +import java.util.WeakHashMap; + +/** + * Created by yboyar on 11/8/14. + */ +public class DataBinder { + + static DataBinderMapper sMapper; + + private WeakHashMap mDataBinderMap = new WeakHashMap<>(); + + private SparseArray> mDataBinderById = new SparseArray<>(); + + private static DataBinderMapper getMapper() { + if (sMapper != null) { + return sMapper; + } + try { + sMapper = (DataBinderMapper) DataBinder.class.getClassLoader() + .loadClass( + "com.android.databinding.GeneratedDataBinderRenderer") + .newInstance(); + } catch (Throwable t) { + throw new RuntimeException(t); + } + return sMapper; + } + + public static int convertToId(String key) { + return getMapper().getId(key); + } + + public View inflate(Context context, int layoutId) { + View view = LayoutInflater.from(context).inflate(layoutId, null); + ViewDataBinder dataBinder = getMapper().getDataBinder(view, layoutId); + if (dataBinder != null) { + mDataBinderMap.put(view, dataBinder); + mDataBinderById.put(layoutId, new WeakReference<>(dataBinder)); + } + return view; + } + + public boolean setVariable(View view, String name, Object variable) { + ViewDataBinder binder = getDataBinder(view); + if (binder == null) { + return false; + } + final int nameId = convertToId(name); + if (nameId == -1) { + return false; + } + return binder.setVariable(nameId, variable); + } + + public boolean setVariable(int layoutId, String name, Object variable) { + ViewDataBinder binder = getDataBinder(layoutId); + if (binder == null) { + return false; + } + final int nameId = convertToId(name); + if (nameId == -1) { + return false; + } + return binder.setVariable(nameId, variable); + } + + public ViewDataBinder getDataBinder(View view) { + return mDataBinderMap.get(view); + } + + public T getDataBinderI(Class klass, View view) { + return (T) getDataBinder(view); + } + + public T getDataBinderI(Class klass, int layoutId) { + return (T) getDataBinder(layoutId); + } + + public static ViewDataBinder createBinder(Context context, int layoutId, ViewGroup parent) { + return getMapper() + .getDataBinder(LayoutInflater.from(context).inflate(layoutId, parent, false), + layoutId); + } + @SuppressWarnings("unchecked") + public static T createBinder(Class klass, Context context, int layoutId, ViewGroup parent) { + return (T) createBinder(context, layoutId, parent); + } + + public ViewDataBinder getDataBinder(int layoutId) { + WeakReference weakReference = mDataBinderById.get(layoutId); + if (weakReference == null) { + return null; + } + return weakReference.get(); + } +} diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/DataBinderMapper.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/DataBinderMapper.java new file mode 100644 index 0000000..60fe165 --- /dev/null +++ b/tools/data-binding/library/src/main/java/com/android/databinding/library/DataBinderMapper.java @@ -0,0 +1,11 @@ +package com.android.databinding.library; + +import android.view.View; + +/** + * Created by yboyar on 11/8/14. + */ +public interface DataBinderMapper { + ViewDataBinder getDataBinder(View view, int layoutId); + public int getId(String key); +} diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/IViewDataBinder.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/IViewDataBinder.java new file mode 100644 index 0000000..9f3adca --- /dev/null +++ b/tools/data-binding/library/src/main/java/com/android/databinding/library/IViewDataBinder.java @@ -0,0 +1,11 @@ +package com.android.databinding.library; + +import android.view.View; + +/** + * Created by yboyar on 11/14/14. + */ +public interface IViewDataBinder { + public View getRoot(); + public abstract void rebindDirty(); +} diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/Observable.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/Observable.java new file mode 100644 index 0000000..ad43388 --- /dev/null +++ b/tools/data-binding/library/src/main/java/com/android/databinding/library/Observable.java @@ -0,0 +1,9 @@ +package com.android.databinding.library; + +/** + * Created by yboyar on 11/9/14. + */ +public interface Observable { + public void register(ObservableListener listener); + public void unRegister(ObservableListener listener); +} diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/ObservableHelper.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/ObservableHelper.java new file mode 100644 index 0000000..78b4755 --- /dev/null +++ b/tools/data-binding/library/src/main/java/com/android/databinding/library/ObservableHelper.java @@ -0,0 +1,53 @@ +package com.android.databinding.library; + +import java.util.concurrent.CopyOnWriteArraySet; + +/** + * Created by yboyar on 11/19/14. + */ +public class ObservableHelper implements Observable { + final Observable owner; + CopyOnWriteArraySet mListeners; + + public ObservableHelper(Observable owner) { + this.owner = owner; + } + + private synchronized CopyOnWriteArraySet getListeners(boolean createIfMissing) { + if (mListeners == null) { + if (createIfMissing) { + mListeners = new CopyOnWriteArraySet<>(); + } + } + return mListeners; + } + + public void fireChange() { + fireChange(""); + } + public void fireChange(String fieldName) { + fireChange(DataBinder.convertToId(fieldName)); + } + public void fireChange(int fieldId) { + final CopyOnWriteArraySet listeners = getListeners(false); + if (listeners == null) { + return; + } + for (ObservableListener listener : listeners) { + listener.onChange(fieldId); + } + } + + @Override + public void register(ObservableListener listener) { + getListeners(true).add(listener); + } + + @Override + public void unRegister(ObservableListener listener) { + final CopyOnWriteArraySet listeners = getListeners(false); + if (listener != null) { + listeners.remove(listener); + } + } +} diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/ObservableListener.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/ObservableListener.java new file mode 100644 index 0000000..3fa618d --- /dev/null +++ b/tools/data-binding/library/src/main/java/com/android/databinding/library/ObservableListener.java @@ -0,0 +1,9 @@ +package com.android.databinding.library; + +/** + * Created by yboyar on 11/9/14. + */ +public interface ObservableListener { + public void onChange(); + public void onChange(int fieldId); +} diff --git a/tools/data-binding/library/src/main/java/com/android/databinding/library/ViewDataBinder.java b/tools/data-binding/library/src/main/java/com/android/databinding/library/ViewDataBinder.java new file mode 100644 index 0000000..71bbb15 --- /dev/null +++ b/tools/data-binding/library/src/main/java/com/android/databinding/library/ViewDataBinder.java @@ -0,0 +1,155 @@ +package com.android.databinding.library; + +import android.util.SparseIntArray; +import android.view.View; + +import java.lang.Override; +import java.lang.Runnable; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by yboyar on 11/8/14. + */ +abstract public class ViewDataBinder { + WeakReferencedListener[] mLocalFieldObservers; + protected abstract boolean onFieldChange(int mLocalFieldId, Object object, int fieldId); + public abstract boolean setVariable(int variableId, Object variable); + public abstract void rebindDirty(); + private final View mRoot; + + private boolean mPendingRebind = false; + private Runnable mRebindRunnable = new Runnable() { + @Override + public void run() { + rebindDirty(); + mPendingRebind = false; + } + }; + + public ViewDataBinder(View root, int localFieldCount) { + mLocalFieldObservers = new WeakReferencedListener[localFieldCount]; + mRoot = root; + } + + public View getRoot() { + return mRoot; + } + + private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) { + boolean result = onFieldChange(mLocalFieldId, object, fieldId); + if (result) { + requestRebind(); + } + } + + protected boolean unregisterFrom(int localFieldId) { + WeakReferencedListener listener = mLocalFieldObservers[localFieldId]; + if (listener != null) { + return listener.unregister(); + } + return false; + } + + protected void requestRebind() { + if (mPendingRebind) { + return; + } + mPendingRebind = true; + mRoot.postOnAnimation(mRebindRunnable); + } + + protected Object getObservedField(int localFieldId) { + WeakReferencedListener listener = mLocalFieldObservers[localFieldId]; + if (listener == null) { + return null; + } + return listener.getTarget(); + } + + protected boolean updateRegistration(int localFieldId, Observable observable) { + if (observable == null) { + return unregisterFrom(localFieldId); + } + WeakReferencedListener listener = mLocalFieldObservers[localFieldId]; + if (listener == null) { + registerTo(localFieldId, observable); + return true; + } + if (listener.getTarget() == observable) { + return false;//nothing to do, same object + } + unregisterFrom(localFieldId); + registerTo(localFieldId, observable); + return true; + } + + protected void registerTo(int localFieldId, Observable observable) { + if (observable == null) { + return; + } + WeakReferencedListener listener = mLocalFieldObservers[localFieldId]; + if (listener == null) { + listener = new ObservableFieldListener(localFieldId); + mLocalFieldObservers[localFieldId] = listener; + } + listener.setTarget(observable); + } + + protected abstract class WeakReferencedListener implements ObservableListener { + WeakReference mTarget; + + public WeakReferencedListener() { + } + + public void setTarget(Observable observable) { + if (observable != null) { + mTarget = new WeakReference<>(observable); + observable.register(this); + } else { + mTarget = null; + } + } + + public boolean unregister() { + Observable oldTarget = getTarget(); + if (oldTarget != null) { + oldTarget.unRegister(this); + } + mTarget = null; + return oldTarget != null; + } + + Observable getTarget() { + return mTarget == null ? null : mTarget.get(); + } + } + + protected class ObservableFieldListener extends WeakReferencedListener { + final int mLocalFieldId; + public ObservableFieldListener(int localFieldId) { + mLocalFieldId = localFieldId; + } + + @Override + public void onChange() { + Observable obj = getTarget(); + if (obj == null) { + return;//how come i live if it died ? + } + ViewDataBinder.this.handleFieldChange(mLocalFieldId, obj, 0); + } + + @Override + public void onChange(int fieldId) { + Observable obj = getTarget(); + if (obj == null) { + return;//how come i live if it died ? + } + ViewDataBinder.this.handleFieldChange(mLocalFieldId, obj, fieldId); + } + } +} diff --git a/tools/data-binding/settings.gradle b/tools/data-binding/settings.gradle new file mode 100644 index 0000000..3f3063f --- /dev/null +++ b/tools/data-binding/settings.gradle @@ -0,0 +1,9 @@ +rootProject.name = 'KDataBinder' + +include ':grammerBuilder' + +include 'library' + +include 'compiler' +include 'gradlePlugin' + -- cgit v1.1 From e09ceae524452d0efe9f9ea3642431a2dcbf2aa6 Mon Sep 17 00:00:00 2001 From: Yigit Boyar Date: Thu, 11 Dec 2014 15:40:13 -0800 Subject: add demo app --- tools/data-binding/BindingDemo/.gitignore | 6 + tools/data-binding/BindingDemo/app/.gitignore | 1 + tools/data-binding/BindingDemo/app/build.gradle | 34 ++++ .../BindingDemo/app/proguard-rules.pro | 17 ++ .../BindingDemo/app/src/main/AndroidManifest.xml | 21 +++ .../android/bindingdemo/DataBoundAdapter.java | 31 +++ .../birbit/android/bindingdemo/MainActivity.java | 208 +++++++++++++++++++++ .../com/birbit/android/bindingdemo/vo/User.java | 76 ++++++++ .../com/birbit/android/bindingdemo/vo/Users.java | 25 +++ .../app/src/main/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 9397 bytes .../app/src/main/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 5237 bytes .../src/main/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 14383 bytes .../src/main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 19388 bytes .../BindingDemo/app/src/main/res/drawable/adam.png | Bin 0 -> 63015 bytes .../BindingDemo/app/src/main/res/drawable/alan.png | Bin 0 -> 56748 bytes .../BindingDemo/app/src/main/res/drawable/chet.png | Bin 0 -> 60114 bytes .../app/src/main/res/drawable/chris.png | Bin 0 -> 59054 bytes .../app/src/main/res/drawable/george.png | Bin 0 -> 65594 bytes .../BindingDemo/app/src/main/res/drawable/john.png | Bin 0 -> 62331 bytes .../BindingDemo/app/src/main/res/drawable/rob.png | Bin 0 -> 67191 bytes .../app/src/main/res/drawable/romain.png | Bin 0 -> 62941 bytes .../app/src/main/res/drawable/tenghui.png | Bin 0 -> 64948 bytes .../app/src/main/res/drawable/yigit.png | Bin 0 -> 80129 bytes .../app/src/main/res/layout/list_item.xml | 30 +++ .../app/src/main/res/layout/main_activity.xml | 119 ++++++++++++ .../app/src/main/res/menu/menu_main.xml | 6 + .../app/src/main/res/values-w820dp/dimens.xml | 6 + .../BindingDemo/app/src/main/res/values/dimens.xml | 10 + .../app/src/main/res/values/strings.xml | 12 ++ .../BindingDemo/app/src/main/res/values/styles.xml | 8 + tools/data-binding/BindingDemo/build.gradle | 23 +++ tools/data-binding/BindingDemo/gradle.properties | 18 ++ .../BindingDemo/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + tools/data-binding/BindingDemo/gradlew | 164 ++++++++++++++++ tools/data-binding/BindingDemo/gradlew.bat | 90 +++++++++ tools/data-binding/BindingDemo/settings.gradle | 1 + .../databinding/library/ViewDataBinder.java | 3 - 38 files changed, 912 insertions(+), 3 deletions(-) create mode 100644 tools/data-binding/BindingDemo/.gitignore create mode 100644 tools/data-binding/BindingDemo/app/.gitignore create mode 100644 tools/data-binding/BindingDemo/app/build.gradle create mode 100644 tools/data-binding/BindingDemo/app/proguard-rules.pro create mode 100644 tools/data-binding/BindingDemo/app/src/main/AndroidManifest.xml create mode 100644 tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/DataBoundAdapter.java create mode 100644 tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/MainActivity.java create mode 100644 tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/vo/User.java create mode 100644 tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/vo/Users.java create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/drawable-hdpi/ic_launcher.png create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/drawable-mdpi/ic_launcher.png create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/drawable/adam.png create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/drawable/alan.png create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/drawable/chet.png create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/drawable/chris.png create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/drawable/george.png create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/drawable/john.png create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/drawable/rob.png create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/drawable/romain.png create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/drawable/tenghui.png create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/drawable/yigit.png create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/layout/list_item.xml create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/layout/main_activity.xml create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/menu/menu_main.xml create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/values-w820dp/dimens.xml create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/values/dimens.xml create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/values/strings.xml create mode 100644 tools/data-binding/BindingDemo/app/src/main/res/values/styles.xml create mode 100644 tools/data-binding/BindingDemo/build.gradle create mode 100644 tools/data-binding/BindingDemo/gradle.properties create mode 100644 tools/data-binding/BindingDemo/gradle/wrapper/gradle-wrapper.jar create mode 100644 tools/data-binding/BindingDemo/gradle/wrapper/gradle-wrapper.properties create mode 100755 tools/data-binding/BindingDemo/gradlew create mode 100644 tools/data-binding/BindingDemo/gradlew.bat create mode 100644 tools/data-binding/BindingDemo/settings.gradle (limited to 'tools') diff --git a/tools/data-binding/BindingDemo/.gitignore b/tools/data-binding/BindingDemo/.gitignore new file mode 100644 index 0000000..afbdab3 --- /dev/null +++ b/tools/data-binding/BindingDemo/.gitignore @@ -0,0 +1,6 @@ +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build diff --git a/tools/data-binding/BindingDemo/app/.gitignore b/tools/data-binding/BindingDemo/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/tools/data-binding/BindingDemo/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/tools/data-binding/BindingDemo/app/build.gradle b/tools/data-binding/BindingDemo/app/build.gradle new file mode 100644 index 0000000..c5e740a --- /dev/null +++ b/tools/data-binding/BindingDemo/app/build.gradle @@ -0,0 +1,34 @@ +apply plugin: 'com.android.application' +apply plugin: 'com.birbit.android.databinding' + +android { + compileSdkVersion 21 + buildToolsVersion "21.1.1" + + defaultConfig { + applicationId "com.birbit.android.bindingdemo" + minSdkVersion 15 + targetSdkVersion 21 + versionCode 1 + versionName "1.0" + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:21+' + compile 'com.birbit.android.databinding:library:0.1-SNAPSHOT@aar' + compile 'com.android.support:recyclerview-v7:21+' + compile 'com.android.support:gridlayout-v7:21+' + compile 'com.android.support:cardview-v7:21+' +} diff --git a/tools/data-binding/BindingDemo/app/proguard-rules.pro b/tools/data-binding/BindingDemo/app/proguard-rules.pro new file mode 100644 index 0000000..b7210d1 --- /dev/null +++ b/tools/data-binding/BindingDemo/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/yboyar/android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/tools/data-binding/BindingDemo/app/src/main/AndroidManifest.xml b/tools/data-binding/BindingDemo/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..15e9dd0 --- /dev/null +++ b/tools/data-binding/BindingDemo/app/src/main/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + diff --git a/tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/DataBoundAdapter.java b/tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/DataBoundAdapter.java new file mode 100644 index 0000000..3539795 --- /dev/null +++ b/tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/DataBoundAdapter.java @@ -0,0 +1,31 @@ +package com.birbit.android.bindingdemo; + +import android.support.v7.widget.RecyclerView; +import android.view.ViewGroup; + +import com.birbit.android.databinding.library.DataBinder; +import com.birbit.android.databinding.library.IViewDataBinder; + +abstract public class DataBoundAdapter + extends RecyclerView.Adapter> { + final int mLayoutId; + final Class mBinderInterface; + public DataBoundAdapter(int mLayoutId, Class mBinderInterface) { + this.mLayoutId = mLayoutId; + this.mBinderInterface = mBinderInterface; + } + + @Override + public DataBoundAdapter.DataBoundViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) { + T binder = DataBinder.createBinder(mBinderInterface, viewGroup.getContext(), mLayoutId, viewGroup); + return new DataBoundViewHolder(binder); + } + + static class DataBoundViewHolder extends RecyclerView.ViewHolder { + public final T dataBinder; + public DataBoundViewHolder(T mViewBinder) { + super(mViewBinder.getRoot()); + this.dataBinder = mViewBinder; + } + } +} diff --git a/tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/MainActivity.java b/tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/MainActivity.java new file mode 100644 index 0000000..234fbc0 --- /dev/null +++ b/tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/MainActivity.java @@ -0,0 +1,208 @@ +package com.birbit.android.bindingdemo; + +import android.support.v7.app.ActionBarActivity; +import android.os.Bundle; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import com.birbit.android.bindingdemo.generated.BR; +import com.birbit.android.bindingdemo.generated.ListItemBinder; +import com.birbit.android.bindingdemo.generated.MainActivityBinder; +import com.birbit.android.bindingdemo.vo.User; +import com.birbit.android.bindingdemo.vo.Users; +import com.birbit.android.databinding.library.DataBinder; +import com.birbit.android.databinding.library.Observable; +import com.birbit.android.databinding.library.ObservableHelper; +import com.birbit.android.databinding.library.ObservableListener; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + + +public class MainActivity extends ActionBarActivity implements Observable { + UserAdapter tkAdapter; + UserAdapter robotAdapter; + MainActivityBinder dataBinder; + User selected; + ObservableHelper helper; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + helper = new ObservableHelper(this); + dataBinder = DataBinder.createBinder(MainActivityBinder.class, this, R.layout.main_activity, null); + setContentView(dataBinder.getRoot()); + tkAdapter = new UserAdapter(Users.toolkities); + robotAdapter = new UserAdapter(Users.robots); + dataBinder.getToolkittyList().setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); + dataBinder.getRobotList().setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); + dataBinder.setActivity(this); + dataBinder.rebindDirty(); + } + + public UserAdapter getTkAdapter() { + return tkAdapter; + } + + public UserAdapter getRobotAdapter() { + return robotAdapter; + } + + public User getSelected() { + return selected; + } + + private void setSelected(User selected) { + if (selected == this.selected) { + return; + } + this.selected = selected; + helper.fireChange(BR.selected); + } + + public View.OnClickListener onSave = new View.OnClickListener() { + @Override + public void onClick(View v) { + if (selected == null) { + return; + } + selected.setName(dataBinder.getSelectedName().getText().toString()); + selected.setLastName(dataBinder.getSelectedLastname().getText().toString()); + } + }; + + public View.OnClickListener onUnselect = new View.OnClickListener() { + + @Override + public void onClick(View v) { + setSelected(null); + } + }; + + public View.OnClickListener onDelete = new View.OnClickListener() { + @Override + public void onClick(View v) { + if (selected == null) { + return; + } + if (selected.getGroup() == User.TOOLKITTY) { + tkAdapter.remove(selected); + selected.setGroup(User.ROBOT); + robotAdapter.add(selected); + dataBinder.getRobotList().smoothScrollToPosition(robotAdapter.getItemCount() - 1); + } else { + tkAdapter.add(selected); + dataBinder.getToolkittyList().smoothScrollToPosition(tkAdapter.getItemCount() - 1); + selected.setGroup(User.TOOLKITTY); + robotAdapter.remove(selected); + } + } + }; + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + + //noinspection SimplifiableIfStatement + if (id == R.id.action_settings) { + return true; + } + + return super.onOptionsItemSelected(item); + } + + @Override + public void register(ObservableListener observableListener) { + helper.register(observableListener); + } + + @Override + public void unRegister(ObservableListener observableListener) { + helper.unRegister(observableListener); + } + + public class UserAdapter extends DataBoundAdapter implements View.OnClickListener, Observable { + List userList = new ArrayList<>(); + ObservableHelper mHelper; + public UserAdapter(User[] toolkities) { + super(R.layout.list_item, ListItemBinder.class); + mHelper = new ObservableHelper(this); + userList.addAll(Arrays.asList(toolkities)); + } + + @Override + public DataBoundViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) { + DataBoundViewHolder vh = super.onCreateViewHolder(viewGroup, type); + vh.dataBinder.setClickListener(this); + return vh; + } + + @Override + public void onBindViewHolder(DataBoundViewHolder vh, int index) { + vh.dataBinder.setUser(userList.get(index)); + vh.dataBinder.rebindDirty(); + } + + @Override + public int getItemCount() { + return userList.size(); + } + + public void add(User user) { + if (userList.contains(user)) { + return; + } + userList.add(user); + notifyItemInserted(userList.size() - 1); + mHelper.fireChange("itemCount"); + } + + public void remove(User user) { + int i = userList.indexOf(user); + if (i < 0) { + return; + } + userList.remove(i); + notifyItemRemoved(i); + mHelper.fireChange("itemCount"); + } + + @Override + public void onClick(View v) { + RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) v.getLayoutParams(); + final int pos = lp.getViewPosition(); + if (pos > -1 && pos < userList.size()) { + v.requestFocus(); + setSelected(userList.get(pos)); + } else { + setSelected(null); + } + } + + @Override + public void register(ObservableListener observableListener) { + mHelper.register(observableListener); + } + + @Override + public void unRegister(ObservableListener observableListener) { + mHelper.unRegister(observableListener); + } + } +} diff --git a/tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/vo/User.java b/tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/vo/User.java new file mode 100644 index 0000000..a805c77 --- /dev/null +++ b/tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/vo/User.java @@ -0,0 +1,76 @@ +package com.birbit.android.bindingdemo.vo; + +import android.graphics.Color; + +import com.birbit.android.databinding.library.BaseObservable; + +import java.util.Objects; + +public class User extends BaseObservable { + private String name; + private String lastName; + private int photoResource = 0; + private int favoriteColor = Color.RED; + private int group; + public static final int TOOLKITTY = 1; + public static final int ROBOT = 2; + + public User(String name, String lastName, int photoResource, int group) { + this.name = name; + this.lastName = lastName; + this.photoResource = photoResource; + this.group = group; + } + + public void setGroup(int group) { + if (this.group == group) { + return; + } + this.group = group; + fireChange("group"); + } + + public int getGroup() { + return group; + } + + public String getName() { + return name; + } + + public void setName(String name) { + if (Objects.equals(name, this.name)) { + return; + } + this.name = name; + fireChange("name"); + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + if (Objects.equals(lastName, this.lastName)) { + return; + } + this.lastName = lastName; + fireChange("lastName"); + } + + public int getPhotoResource() { + return photoResource; + } + + public void setPhotoResource(int photoResource) { + if (this.photoResource == photoResource) { + return; + } + this.photoResource = photoResource; + fireChange("photoResource"); + } + + public int getFavoriteColor() { + return favoriteColor; + } +} diff --git a/tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/vo/Users.java b/tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/vo/Users.java new file mode 100644 index 0000000..c7b6647 --- /dev/null +++ b/tools/data-binding/BindingDemo/app/src/main/java/com/birbit/android/bindingdemo/vo/Users.java @@ -0,0 +1,25 @@ +package com.birbit.android.bindingdemo.vo; + +import com.birbit.android.bindingdemo.R; + +/** + * Created by yboyar on 11/19/14. + */ +public class Users { + public static final User[] robots = new User[]{ + new User("romain", "guy", R.drawable.romain, User.ROBOT), + }; + public static final User[] toolkities = new User[]{ + new User("chet", "haase", R.drawable.chet, User.TOOLKITTY), + new User("adam", "powell", R.drawable.adam, User.TOOLKITTY), + new User("alan", "viverette", R.drawable.alan, User.TOOLKITTY), + new User("chris", "craik", R.drawable.chris, User.TOOLKITTY), + new User("george", "mount", R.drawable.george, User.TOOLKITTY), + new User("john", "reck", R.drawable.john, User.TOOLKITTY), + new User("rob", "tsuk", R.drawable.rob, User.TOOLKITTY), + new User("Teng-Hui", "Zhu", R.drawable.tenghui, User.TOOLKITTY), + new User("yigit", "boyar", R.drawable.yigit, User.TOOLKITTY), + + + }; +} diff --git a/tools/data-binding/BindingDemo/app/src/main/res/drawable-hdpi/ic_launcher.png b/tools/data-binding/BindingDemo/app/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000..96a442e Binary files /dev/null and b/tools/data-binding/BindingDemo/app/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/tools/data-binding/BindingDemo/app/src/main/res/drawable-mdpi/ic_launcher.png b/tools/data-binding/BindingDemo/app/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000..359047d Binary files /dev/null and b/tools/data-binding/BindingDemo/app/src/main/res/drawable-mdpi/ic_launcher.png differ diff --git a/tools/data-binding/BindingDemo/app/src/main/res/drawable-xhdpi/ic_launcher.png b/tools/data-binding/BindingDemo/app/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000..71c6d76 Binary files /dev/null and b/tools/data-binding/BindingDemo/app/src/main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/tools/data-binding/BindingDemo/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/tools/data-binding/BindingDemo/app/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..4df1894 Binary files /dev/null and b/tools/data-binding/BindingDemo/app/src/main/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/tools/data-binding/BindingDemo/app/src/main/res/drawable/adam.png b/tools/data-binding/BindingDemo/app/src/main/res/drawable/adam.png new file mode 100644 index 0000000..583a065 Binary files /dev/null and b/tools/data-binding/BindingDemo/app/src/main/res/drawable/adam.png differ diff --git a/tools/data-binding/BindingDemo/app/src/main/res/drawable/alan.png b/tools/data-binding/BindingDemo/app/src/main/res/drawable/alan.png new file mode 100644 index 0000000..c0c9161 Binary files /dev/null and b/tools/data-binding/BindingDemo/app/src/main/res/drawable/alan.png differ diff --git a/tools/data-binding/BindingDemo/app/src/main/res/drawable/chet.png b/tools/data-binding/BindingDemo/app/src/main/res/drawable/chet.png new file mode 100644 index 0000000..06cc751 Binary files /dev/null and b/tools/data-binding/BindingDemo/app/src/main/res/drawable/chet.png differ diff --git a/tools/data-binding/BindingDemo/app/src/main/res/drawable/chris.png b/tools/data-binding/BindingDemo/app/src/main/res/drawable/chris.png new file mode 100644 index 0000000..11686c5 Binary files /dev/null and b/tools/data-binding/BindingDemo/app/src/main/res/drawable/chris.png differ diff --git a/tools/data-binding/BindingDemo/app/src/main/res/drawable/george.png b/tools/data-binding/BindingDemo/app/src/main/res/drawable/george.png new file mode 100644 index 0000000..fe744e0 Binary files /dev/null and b/tools/data-binding/BindingDemo/app/src/main/res/drawable/george.png differ diff --git a/tools/data-binding/BindingDemo/app/src/main/res/drawable/john.png b/tools/data-binding/BindingDemo/app/src/main/res/drawable/john.png new file mode 100644 index 0000000..7bd0108 Binary files /dev/null and b/tools/data-binding/BindingDemo/app/src/main/res/drawable/john.png differ diff --git a/tools/data-binding/BindingDemo/app/src/main/res/drawable/rob.png b/tools/data-binding/BindingDemo/app/src/main/res/drawable/rob.png new file mode 100644 index 0000000..fd41cb0 Binary files /dev/null and b/tools/data-binding/BindingDemo/app/src/main/res/drawable/rob.png differ diff --git a/tools/data-binding/BindingDemo/app/src/main/res/drawable/romain.png b/tools/data-binding/BindingDemo/app/src/main/res/drawable/romain.png new file mode 100644 index 0000000..7a9af15 Binary files /dev/null and b/tools/data-binding/BindingDemo/app/src/main/res/drawable/romain.png differ diff --git a/tools/data-binding/BindingDemo/app/src/main/res/drawable/tenghui.png b/tools/data-binding/BindingDemo/app/src/main/res/drawable/tenghui.png new file mode 100644 index 0000000..13442b0 Binary files /dev/null and b/tools/data-binding/BindingDemo/app/src/main/res/drawable/tenghui.png differ diff --git a/tools/data-binding/BindingDemo/app/src/main/res/drawable/yigit.png b/tools/data-binding/BindingDemo/app/src/main/res/drawable/yigit.png new file mode 100644 index 0000000..57e9baf Binary files /dev/null and b/tools/data-binding/BindingDemo/app/src/main/res/drawable/yigit.png differ diff --git a/tools/data-binding/BindingDemo/app/src/main/res/layout/list_item.xml b/tools/data-binding/BindingDemo/app/src/main/res/layout/list_item.xml new file mode 100644 index 0000000..351db09 --- /dev/null +++ b/tools/data-binding/BindingDemo/app/src/main/res/layout/list_item.xml @@ -0,0 +1,30 @@ + + + + + + \ No newline at end of file diff --git a/tools/data-binding/BindingDemo/app/src/main/res/layout/main_activity.xml b/tools/data-binding/BindingDemo/app/src/main/res/layout/main_activity.xml new file mode 100644 index 0000000..02513ef --- /dev/null +++ b/tools/data-binding/BindingDemo/app/src/main/res/layout/main_activity.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + +