Hi Andrew, I just had a quick go at doing this locally. I *think* it should
be able to be done in MXMLRoyaleEmitter with minor changes.

I have not tested extensively, so I will just describe what I did and you
can see if it works, and if it is universally applicable.

The following is what I did:

change the
encodeWatcher method signature to this:
private void encodeWatcher(WatcherInfoBase watcherInfoBase, IDefinition
sourceDefinition)

and make 2 changes inside that method:

#1.
for the part that is:
 writeNewline(ASEmitterTokens.DOUBLE_QUOTE.getToken() +
propertyWatcherInfo.getPropertyName() +
                    ASEmitterTokens.DOUBLE_QUOTE.getToken() +
ASEmitterTokens.COMMA.getToken());

replace with this:

            String outputName = propertyWatcherInfo.getPropertyName();
            if (sourceDefinition != null && sourceDefinition.isPrivate() &&
getMXMLWalker().getProject().getAllowPrivateNameConflicts()) {
JSRoyaleEmitter fjs = (JSRoyaleEmitter) ((IMXMLBlockWalker) getMXMLWalker())
.getASEmitter();
outputName =
fjs.formatPrivateName(sourceDefinition.getParent().getQualifiedName(),
outputName);
}
            writeNewline(ASEmitterTokens.DOUBLE_QUOTE.getToken() +
outputName +
                    ASEmitterTokens.DOUBLE_QUOTE.getToken() +
ASEmitterTokens.COMMA.getToken());


#2
further down, comply with the new method signature:
replace:
 encodeWatcher(ent.getValue());

with:
IDefinition childSourceDefinition = (IDefinition) ent.getKey();
                encodeWatcher(ent.getValue(), childSourceDefinition);



And also in
outputBindingInfoAsData method:
comply with the new method signature for encodeWatcher

  IDefinition sourceDefinition = (IDefinition) entry.getKey();
                encodeWatcher(watcherInfoBase, sourceDefinition);


I think that might work for the general case, and maybe it can be
simplified. I only tested quickly and just looked at the output, did not
actually try the resulting app. If this does not work, it might give you a
lead.
-Greg

On Fri, Dec 7, 2018 at 7:58 AM Alex Harui <aha...@adobe.com.invalid> wrote:

> 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
>
>
>
>
>
>

Reply via email to