Hi Andrew, Thanks for looking into this.
One of the things to keep in mind about the compiler that isn't immediately obvious is that the JS compiler can be thought of almost as a subclass of the SWF compiler. It isn't truly that way in the code, but the way it is now, even if you don't want SWF output, we actually run the most of the SWF compiler tasks on the source code before generating the JS because the transpiler's AST walk (that uses the Emitters to generate the JS) does not have the smarts for semantic analysis and similar things like binding and watcher analysis. The clue to that is which Eclipse projects or jars the various source files belong to. We will try not to introduce any files from the compiler-jx project/jar into the compiler and compiler-common project/jars. Doing so could create build order/dependency issues. And thus, we don't want to access the Emitters from the WatcherAnalyzer, nor have the WatcherAnalyzer know that it is talking to a RoyaleJSProject instead of a RoyaleProject (the latter which is designed for SWF output). And, even if you did find a way to access the Emitter, I think the same Watcher database is used for SWF output as well, so you don't always want to decorate the name of private variables in the data structure. After a quick think, I would suggest doing a bit more digging. I noticed that in the snippet you posted, a getter function appeared to be correctly generated. Is that part of the Watcher data or the Binding data? In the ActionScript code (DataBindingBase and subclasses) the Binding data is supposed to discriminate between "simple" property chains that it can create more efficient Bindings for vs GenericBinding that can handle more complex cases. The idea is that in some cases, we can't just access the value by an instance.propName lookup and a getterFunction is generated instead. This is absolutely required in SWF code since external classes like the Binding classes can't access private members of the class it is watching. It has always felt like a "cheat" to me that Binding pokes holes in the private access protection for Bindings, but that's pretty much the only way we can do it in SWF code (which also sort of means you lose the advantage of binding to private variables in the first place). In fact, I think one of the optimizations for Royale binding will be that bindings will be faster/smaller on public variables than private variables. So, having said all that, one possible solution is to have the ActionScript code use the getter function instead of the propertyName for private variables. I thought that the transpiler did not always output a getter function if public property chains could access the value. The AS code could then know to use a function instead of the property name. If some future version of JS actually does provide private access protection someday, we'll be glad we did this. Right now, the Royale JS binding code has been relying on direct access to private variables, which is also a "cheat", IMO. Another possible approach is to change what is stored in the Watcher database. Add new fields to store the fact that the property is private. Then in MXMLRoyaleEmitter, the watcher output code should have access to an emitter, and there is no need to access compiler-jx classes from the WatcherAnalyzer. This approach (just adding more info in the shared Analyzer code instead of generating code) is probably more platform/output-independent. Or maybe you'll need both. Hope that made sense. Good luck, -Alex On 12/6/18, 6:30 AM, "Frost, Andrew" <andrew.fr...@harman.com> wrote: Hi all I found recently that binding had stopped working when we were using private variables, for example: <test:TestComponent id="testing" width="100" height="20" boundValue="{_model.value}"> where we declare: private var _model : Model = Model.getModel(); However it works with protected/public variables.. The reason is clear when you look at the generated _bindings array, which contains: function() { return this.test_MainView__model.value; }, and then "_model", "valueChange", So basically the watcher list is using "_model" whereas the property is actually generated as "test_MainView__model". Looking at the compiler code, there's a function on the emitter which does this translation: public String formatPrivateName(String className, String name) { return className.replace(".", "_") + "_" + name; } However I can't work out how to get the watcher analyser class to access the emitter.. I think this is where the logic should go, because within "WatcherAnalyzer. analyzeIdentifierNode" we're getting the name as a string and creating the watcher object based on this string. So I want to do: name = def.getBaseName(); if (def.isPrivate() && project.getAllowPrivateNameConflicts()) { name = getEmitter().formatPrivateName(def.getParent().getQualifiedName(), name); } My issue is that there's no access that I can see to the Emitter. So I thought I'd ask: 1. does anyone know how I could actually get a valid reference to the emitter from this point in the code? i.e. just through the JSRoyaleProject object from what I can see.. 2. or is there a better place where this should be? e.g. within getBaseName itself, or where the base name is set up on the definition..? 3. or could we move the "formatPrivateName" method to somewhere more accessible? 4. or can I just reproduce the "formatPrivateName" functionality here, and add comments so that future maintainers know to update two locations in case this changes? The last option is simplest but very hacky.. but would appreciate thoughts on the best approach. thanks Andrew