You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by jo...@apache.org on 2020/12/21 19:30:14 UTC

[royale-compiler] branch develop updated (9235fbc -> baa3ea4)

This is an automated email from the ASF dual-hosted git repository.

joshtynjala pushed a change to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git.


    from 9235fbc  ClosureUtils: fix bindable variables not being detected as accessors
     new 0b7fa3d  JSGoogConfiguration: add allow-dynamic-bindings
     new 3046c63  MXMLRoyaleEmitter: created an emitter interface for MXML specifiers so that their generated JS output may have different implementations
     new baa3ea4  GenerateRoyaleExports: MXML ids generated by the compiler should be exported because they are accessed dynamically by MXMLDataInterpreter (and bindings)

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../javascript/jscomp/GenerateRoyaleExports.java   |  16 ++
 .../compiler/codegen/mxml/js/IMXMLJSEmitter.java   |  13 +-
 .../royale/JSRoyaleBasicMXMLDescriptorEmitter.java | 312 +++++++++++++++++++++
 .../JSSubEmitter.java => mxml/MXMLSubEmitter.java} |  24 +-
 .../mxml/royale/MXMLDescriptorSpecifier.java       | 282 -------------------
 .../codegen/mxml/royale/MXMLEventSpecifier.java    |  18 +-
 .../codegen/mxml/royale/MXMLNodeSpecifier.java     | 114 --------
 .../codegen/mxml/royale/MXMLRoyaleEmitter.java     |  62 ++--
 .../driver/js/goog/JSGoogConfiguration.java        |  20 ++
 9 files changed, 405 insertions(+), 456 deletions(-)
 copy compiler-common/src/main/java/org/apache/royale/compiler/internal/config/localization/ILocalizedText.java => compiler-jx/src/main/java/org/apache/royale/compiler/codegen/mxml/js/IMXMLJSEmitter.java (76%)
 create mode 100644 compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleBasicMXMLDescriptorEmitter.java
 copy compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/{js/JSSubEmitter.java => mxml/MXMLSubEmitter.java} (85%)


[royale-compiler] 03/03: GenerateRoyaleExports: MXML ids generated by the compiler should be exported because they are accessed dynamically by MXMLDataInterpreter (and bindings)

Posted by jo...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

joshtynjala pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git

commit baa3ea4040c0fb7711d5bf48f4f96f2fbab05e26
Author: Josh Tynjala <jo...@apache.org>
AuthorDate: Mon Dec 21 10:51:30 2020 -0800

    GenerateRoyaleExports: MXML ids generated by the compiler should be exported because they are accessed dynamically by MXMLDataInterpreter (and bindings)
---
 .../google/javascript/jscomp/GenerateRoyaleExports.java  | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/compiler-jx/src/main/java/com/google/javascript/jscomp/GenerateRoyaleExports.java b/compiler-jx/src/main/java/com/google/javascript/jscomp/GenerateRoyaleExports.java
index 566f08a..2ef2f19 100644
--- a/compiler-jx/src/main/java/com/google/javascript/jscomp/GenerateRoyaleExports.java
+++ b/compiler-jx/src/main/java/com/google/javascript/jscomp/GenerateRoyaleExports.java
@@ -74,6 +74,22 @@ public class GenerateRoyaleExports extends AbstractPostOrderCallback {
 				addExtern(n.getString());
 				return;
 			}
+			case GETPROP: {
+				String qualifiedName = n.getQualifiedName();
+				if(!qualifiedName.startsWith("this.$ID_")) {
+					return;
+				}
+				Node gp = n.getGrandparent();
+				if(gp == null) {
+					return;
+				}
+				Node ggp = gp.getParent();
+				if(ggp == null || !ggp.isFunction()) {
+					return;
+				}
+				addExtern(n.getOriginalName());
+				return;
+			}
 			case ASSIGN: {
 				Node firstChild = n.getFirstChild();
 				if (!firstChild.isQualifiedName()) {


[royale-compiler] 01/03: JSGoogConfiguration: add allow-dynamic-bindings

Posted by jo...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

joshtynjala pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git

commit 0b7fa3d8855cf1ebc6b1355740226b87d70d7d08
Author: Josh Tynjala <jo...@apache.org>
AuthorDate: Wed Dec 2 12:46:27 2020 -0800

    JSGoogConfiguration: add allow-dynamic-bindings
    
    MXMLRoyaleEmitter: if allow-dynamic-bindings is false, always emits functions instead of strings for dynamic access
---
 .../codegen/mxml/royale/MXMLRoyaleEmitter.java     | 25 +++++++++++++++++++---
 .../driver/js/goog/JSGoogConfiguration.java        | 20 +++++++++++++++++
 2 files changed, 42 insertions(+), 3 deletions(-)

diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java
index 12fdc87..85a0032 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java
@@ -1499,8 +1499,10 @@ public class MXMLRoyaleEmitter extends MXMLEmitter implements
 
     private void outputBindingInfoAsData(String cname, BindingDatabase bindingDataBase)
     {
+        RoyaleJSProject project = (RoyaleJSProject)getMXMLWalker().getProject();
         IASEmitter asEmitter = ((IMXMLBlockWalker) getMXMLWalker())
                 .getASEmitter();
+        boolean allowDynamicBindings = project.config != null && project.config.getAllowDynamicBindings();
         
         writeNewline("/**");
         writeNewline(" * @export"); // must export or else GCC will remove it
@@ -1526,7 +1528,6 @@ public class MXMLRoyaleEmitter extends MXMLEmitter implements
             if (node instanceof IMXMLSingleDataBindingNode)
             {
             	IMXMLSingleDataBindingNode sbdn = (IMXMLSingleDataBindingNode)node;
-            	RoyaleJSProject project = (RoyaleJSProject)getMXMLWalker().getProject();
             	IDefinition bdef = sbdn.getExpressionNode().resolve(project);
             	if (bdef != null)
             	{
@@ -1537,10 +1538,13 @@ public class MXMLRoyaleEmitter extends MXMLEmitter implements
             s = bi.getSourceString();
             if (s == null && bi.isSourceSimplePublicProperty())
                 s = getSourceStringFromGetter(bi.getExpressionNodesForGetter());
-            if (s == null || s.length() == 0)
+            if (!allowDynamicBindings || s == null || s.length() == 0)
             {
                 List<IExpressionNode> getterNodes = bi.getExpressionNodesForGetter();
                 StringBuilder sb = new StringBuilder();
+                sb.append("/** @this {");
+                sb.append(formatQualifiedName(cname));
+                sb.append("} */\n");
                 sb.append("function() { return ");
                 int n = getterNodes.size();
                 for (int i = 0; i < n; i++)
@@ -1593,7 +1597,20 @@ public class MXMLRoyaleEmitter extends MXMLEmitter implements
 
             IExpressionNode destNode = bi.getExpressionNodeForDestination();
             s = bi.getDestinationString();
-            if (destNode != null && s == null)
+            if (!allowDynamicBindings && destNode == null && s != null)
+            {
+                StringBuilder sb = new StringBuilder();
+                sb.append("/** @this {");
+                sb.append(formatQualifiedName(cname));
+                sb.append("} */\n");
+                sb.append("function(value) { ");
+                sb.append("this.");
+                sb.append(s);
+                sb.append(" = value; },");
+                writeNewline(sb.toString());
+                s = null;
+            }
+            else if (destNode != null && s == null)
             {
                 StringBuilder sb = new StringBuilder();
                 sb.append(generateSetterFunction(bi, destNode));
@@ -1620,8 +1637,10 @@ public class MXMLRoyaleEmitter extends MXMLEmitter implements
                 write(ASEmitterTokens.SQUARE_CLOSE.getToken());
             }
             else
+            {
                 write(ASEmitterTokens.DOUBLE_QUOTE.getToken() + s +
                         ASEmitterTokens.DOUBLE_QUOTE.getToken());
+            }
             
         }
         Set<Entry<Object, WatcherInfoBase>> watcherChains = bindingDataBase.getWatcherChains();
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/driver/js/goog/JSGoogConfiguration.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/driver/js/goog/JSGoogConfiguration.java
index e1cdcbe..892cced 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/driver/js/goog/JSGoogConfiguration.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/driver/js/goog/JSGoogConfiguration.java
@@ -865,6 +865,26 @@ public class JSGoogConfiguration extends JSConfiguration
 
     
     //
+    // 'allow-dynamic-bindings'
+    //
+
+    private boolean allowDynamicBindings = true;
+
+    public boolean getAllowDynamicBindings()
+    {
+        return allowDynamicBindings;
+    }
+
+    @Config
+    @Mapping("allow-dynamic-bindings")
+    public void setAllowDynamicBindings(ConfigurationValue cv, boolean value)
+            throws ConfigurationException
+    {
+    	allowDynamicBindings = value;
+    }
+
+    
+    //
     // 'warn-public-vars'
     //
 


[royale-compiler] 02/03: MXMLRoyaleEmitter: created an emitter interface for MXML specifiers so that their generated JS output may have different implementations

Posted by jo...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

joshtynjala pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git

commit 3046c63832f8fb88f6c95e3cac748acdd23c5042
Author: Josh Tynjala <jo...@apache.org>
AuthorDate: Mon Dec 21 10:49:49 2020 -0800

    MXMLRoyaleEmitter: created an emitter interface for MXML specifiers so that their generated JS output may have different implementations
---
 .../compiler/codegen/mxml/js/IMXMLJSEmitter.java   |  27 ++
 .../royale/JSRoyaleBasicMXMLDescriptorEmitter.java | 312 +++++++++++++++++++++
 .../internal/codegen/mxml/MXMLSubEmitter.java      | 125 +++++++++
 .../mxml/royale/MXMLDescriptorSpecifier.java       | 282 -------------------
 .../codegen/mxml/royale/MXMLEventSpecifier.java    |  18 +-
 .../codegen/mxml/royale/MXMLNodeSpecifier.java     | 114 --------
 .../codegen/mxml/royale/MXMLRoyaleEmitter.java     |  37 +--
 7 files changed, 485 insertions(+), 430 deletions(-)

diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/mxml/js/IMXMLJSEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/mxml/js/IMXMLJSEmitter.java
new file mode 100644
index 0000000..4d4dde4
--- /dev/null
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/mxml/js/IMXMLJSEmitter.java
@@ -0,0 +1,27 @@
+/*
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.codegen.mxml.js;
+
+import org.apache.royale.compiler.codegen.js.IMappingEmitter;
+import org.apache.royale.compiler.codegen.mxml.IMXMLEmitter;
+
+public interface IMXMLJSEmitter extends IMXMLEmitter, IMappingEmitter {
+	
+}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleBasicMXMLDescriptorEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleBasicMXMLDescriptorEmitter.java
new file mode 100644
index 0000000..ea11bf7
--- /dev/null
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleBasicMXMLDescriptorEmitter.java
@@ -0,0 +1,312 @@
+/*
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.internal.codegen.js.royale;
+
+import org.apache.royale.compiler.codegen.ISubEmitter;
+import org.apache.royale.compiler.codegen.mxml.js.IMXMLJSEmitter;
+import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
+import org.apache.royale.compiler.internal.codegen.mxml.MXMLSubEmitter;
+import org.apache.royale.compiler.internal.codegen.mxml.royale.MXMLDescriptorSpecifier;
+import org.apache.royale.compiler.internal.codegen.mxml.royale.MXMLEventSpecifier;
+
+public class JSRoyaleBasicMXMLDescriptorEmitter extends MXMLSubEmitter implements ISubEmitter<MXMLDescriptorSpecifier>
+{
+    public JSRoyaleBasicMXMLDescriptorEmitter(IMXMLJSEmitter emitter)
+    {
+        super(emitter);
+    }
+
+    @Override
+    public void emit(MXMLDescriptorSpecifier root)
+    {
+		outputDescriptorSpecifier(root, true);
+	}
+
+    //---------------------------------
+    //    writeSimpleDescriptor
+    //---------------------------------
+
+    protected void writeSimpleDescriptor(String name, String type, String value,
+            boolean writeNewline)
+    {
+        write(ASEmitterTokens.SINGLE_QUOTE);
+        write(name);
+        write(ASEmitterTokens.SINGLE_QUOTE);
+        writeDelimiter(writeNewline);
+
+        if (type != null)
+        {
+            write(type);
+            writeDelimiter(writeNewline);
+        }
+
+        write(value);
+    }
+
+    //---------------------------------
+    //    writeDelimiter
+    //---------------------------------
+
+    protected void writeDelimiter(boolean writeNewline)
+    {
+        if (writeNewline)
+            writeNewline(ASEmitterTokens.COMMA);
+        else
+            writeToken(ASEmitterTokens.COMMA);
+	}
+
+    //---------------------------------
+    //    outputDescriptorSpecifier
+    //---------------------------------
+
+	private void outputDescriptorSpecifier(MXMLDescriptorSpecifier root, boolean writeNewline)
+    {
+        if (root.isTopNode)
+        {
+            int count = 0;
+            for (MXMLDescriptorSpecifier md : root.propertySpecifiers)
+            {
+                if (md.name != null)
+                    count++;
+            }
+
+            write(count + "");
+            writeNewline(ASEmitterTokens.COMMA);
+        }
+
+		outputPropertySpecifiers(root, writeNewline);
+
+        if (!root.isProperty)
+        {
+            outputStyleSpecifiers(root, writeNewline);
+
+            // TODO (erikdebruin) not yet implemented in Royale
+            //outputEffectSpecifiers(writeNewline);
+
+            outputEventSpecifiers(root, writeNewline);
+
+            if (!root.isTopNode)
+            {
+                writeDelimiter(writeNewline);
+
+                if (root.childrenSpecifier == null)
+                    write(ASEmitterTokens.NULL);
+                else
+                    outputChildren(root.childrenSpecifier, writeNewline);
+            }
+
+            boolean isLastChild = root.parent != null
+                    && root.parent.propertySpecifiers.indexOf(root) == root.parent.propertySpecifiers
+                            .size() - 1;
+
+            if (!isLastChild && !root.isTopNode)
+                writeDelimiter(writeNewline);
+        }
+    }
+
+    //---------------------------------
+    //    outputPropertySpecifiers
+    //---------------------------------
+	
+	private void outputPropertySpecifiers(MXMLDescriptorSpecifier root, boolean writeNewline)
+	{
+        MXMLDescriptorSpecifier model = null; // model goes first
+        MXMLDescriptorSpecifier beads = null; // beads go last
+
+        for (MXMLDescriptorSpecifier md : root.propertySpecifiers)
+        {
+            if (md.name != null && md.name.equals("model"))
+            {
+                model = md;
+                break;
+            }
+        }
+
+        if (model != null)
+        {
+            outputPropertySpecifier(model, writeNewline);
+        }
+
+        for (MXMLDescriptorSpecifier md : root.propertySpecifiers)
+        {
+            if (md.name != null)
+            {
+                if (!md.name.equals("model") && !md.name.equals("beads"))
+                    outputPropertySpecifier(md, writeNewline);
+                else if (md.name.equals("beads"))
+                    beads = md;
+            }
+        }
+
+        if (beads != null)
+        {
+            outputPropertySpecifier(beads, writeNewline);
+        }
+	}
+
+    //---------------------------------
+    //    outputEventSpecifiers
+    //---------------------------------
+
+    private void outputEventSpecifiers(MXMLDescriptorSpecifier root, boolean writeNewline)
+    {
+        // number of events
+        int count = 0;
+        for (MXMLEventSpecifier me : root.eventSpecifiers)
+        {
+            if (me.name != null)
+                count++;
+        }
+        write(count + "");
+
+        for (MXMLEventSpecifier me : root.eventSpecifiers)
+        {
+			writeDelimiter(writeNewline);
+			outputEventSpecifier(me, writeNewline);
+        }
+    }
+
+    //---------------------------------
+    //    outputStyleSpecifiers
+    //---------------------------------
+
+    private void outputStyleSpecifiers(MXMLDescriptorSpecifier root, boolean writeNewline)
+    {
+        // TODO (erikdebruin) not yet implemented in Royale
+
+        write("0");
+        writeDelimiter(writeNewline);
+    }
+
+    //---------------------------------
+    //    outputPropertySpecifier
+    //---------------------------------
+
+    private void outputPropertySpecifier(MXMLDescriptorSpecifier specifier, boolean writeNewline)
+    {
+        write((specifier.isProperty) ? ASEmitterTokens.SINGLE_QUOTE.getToken() : "");
+        write(specifier.name);
+        write((specifier.isProperty) ? ASEmitterTokens.SINGLE_QUOTE.getToken() : "");
+        writeDelimiter(writeNewline);
+
+        if (specifier.isProperty)
+        {
+            if (specifier.value != null)
+            {
+                write(ASEmitterTokens.TRUE);
+                writeDelimiter(writeNewline);
+                // need to do other escaping here?
+                // restrict="0-9.\"
+                if (specifier.value.endsWith("\\'") && !specifier.value.endsWith("\\\\'"))
+                {
+                	specifier.value = specifier.value.substring(0, specifier.value.length() - 1) + "\\'";
+                }
+                write(specifier.value);
+            }
+            else
+            {
+                write((specifier.hasArray) ? ASEmitterTokens.NULL : ASEmitterTokens.FALSE);
+                writeDelimiter(writeNewline);
+                write(ASEmitterTokens.SQUARE_OPEN);
+                indentPush();
+                writeNewline();
+                outputDescriptorSpecifier(specifier, writeNewline);
+                indentPop();
+                writeNewline();
+                write(ASEmitterTokens.SQUARE_CLOSE);
+            }
+
+            if (specifier.parent != null)
+                writeDelimiter(writeNewline);
+        }
+        else
+        {
+            for (MXMLDescriptorSpecifier md : specifier.propertySpecifiers)
+            {
+                if (md.name != null && md.name.equals("mxmlContent"))
+                {
+                    specifier.childrenSpecifier = md;
+                    specifier.propertySpecifiers.remove(md);
+                    break;
+                }
+            }
+
+            if (specifier.id != null || specifier.effectiveId != null)
+            {
+                write(specifier.propertySpecifiers.size() + 1 + "");
+                writeDelimiter(writeNewline);
+                String idPropName = (specifier.effectiveId != null) ? "_id"
+                        : "id";
+                writeSimpleDescriptor(idPropName, ASEmitterTokens.TRUE.getToken(),
+                        ASEmitterTokens.SINGLE_QUOTE.getToken()
+                                + ((specifier.id != null) ? specifier.id : specifier.effectiveId) + ASEmitterTokens.SINGLE_QUOTE.getToken(),
+                        writeNewline);
+
+                writeDelimiter(writeNewline);
+            }
+            else
+            {
+                write(specifier.propertySpecifiers.size() + "");
+                writeDelimiter(writeNewline);
+            }
+
+            outputDescriptorSpecifier(specifier, writeNewline);
+        }
+    }
+
+    //---------------------------------
+    //    outputEventSpecifier
+    //---------------------------------
+
+    public void outputEventSpecifier(MXMLEventSpecifier specifier, boolean writeNewline)
+    {
+        String handler = ASEmitterTokens.THIS.getToken()
+                + ASEmitterTokens.MEMBER_ACCESS.getToken() + specifier.eventHandler;
+        if (MXMLEventSpecifier.nameMap.contains(specifier.name))
+			specifier.name = specifier.name.toLowerCase();
+		else if (specifier.name.equals("doubleClick"))
+			specifier.name = "dblclick";
+		else if (specifier.name.equals("mouseWheel"))
+			specifier.name = "wheel";
+        writeSimpleDescriptor(specifier.name, null, handler, writeNewline);
+    }
+
+    //---------------------------------
+    //    outputChildren
+    //---------------------------------
+
+    private void outputChildren(MXMLDescriptorSpecifier children, boolean writeNewline)
+    {
+        write(ASEmitterTokens.SQUARE_OPEN.getToken());
+        if(writeNewline)
+        {
+            indentPush();
+            writeNewline();
+		}
+		outputDescriptorSpecifier(children, writeNewline);
+        if(writeNewline)
+        {
+            indentPop();
+            writeNewline();
+        }
+        write(ASEmitterTokens.SQUARE_CLOSE.getToken());
+	}
+	
+}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/MXMLSubEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/MXMLSubEmitter.java
new file mode 100644
index 0000000..25d7ae2
--- /dev/null
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/MXMLSubEmitter.java
@@ -0,0 +1,125 @@
+/*
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.internal.codegen.mxml;
+
+import org.apache.royale.compiler.codegen.IEmitterTokens;
+import org.apache.royale.compiler.codegen.mxml.js.IMXMLJSEmitter;
+import org.apache.royale.compiler.common.ISourceLocation;
+import org.apache.royale.compiler.projects.ICompilerProject;
+import org.apache.royale.compiler.visitor.IBlockWalker;
+
+public class MXMLSubEmitter {
+    private IMXMLJSEmitter emitter;
+
+    protected IMXMLJSEmitter getEmitter()
+    {
+        return emitter; 
+    }
+
+    protected IBlockWalker getMXMLWalker()
+    {
+        return emitter.getMXMLWalker();
+    }
+    
+    protected ICompilerProject getProject()
+    {
+        return emitter.getMXMLWalker().getProject();
+    }
+
+    public MXMLSubEmitter(IMXMLJSEmitter emitter)
+    {
+        this.emitter = emitter;
+    }
+
+    protected void write(IEmitterTokens value)
+    {
+        emitter.write(value);
+    }
+
+    protected void write(String value)
+    {
+        emitter.write(value);
+    }
+
+    protected void writeToken(IEmitterTokens value)
+    {
+        emitter.writeToken(value);
+    }
+
+    protected void writeToken(String value)
+    {
+        emitter.writeToken(value);
+    }
+
+    protected void writeNewline()
+    {
+        emitter.writeNewline();
+    }
+
+    protected void writeNewline(IEmitterTokens value)
+    {
+        emitter.writeNewline(value);
+    }
+
+    protected void writeNewline(String value)
+    {
+        emitter.writeNewline(value);
+    }
+
+    protected void writeNewline(IEmitterTokens value, boolean pushIndent)
+    {
+        emitter.writeNewline(value, pushIndent);
+    }
+
+    protected void writeNewline(String value, boolean pushIndent)
+    {
+        emitter.writeNewline(value, pushIndent);
+    }
+
+    protected void indentPush()
+    {
+        emitter.indentPush();
+    }
+
+    protected void indentPop()
+    {
+        emitter.indentPop();
+    }
+
+    protected void startMapping(ISourceLocation node)
+    {
+        emitter.startMapping(node);
+    }
+
+    protected void startMapping(ISourceLocation node, int line, int column)
+    {
+        emitter.startMapping(node, line, column);
+    }
+
+    protected void startMapping(ISourceLocation node, ISourceLocation afterNode)
+    {
+        emitter.startMapping(node, afterNode);
+    }
+
+    protected void endMapping(ISourceLocation node)
+    {
+        emitter.endMapping(node);
+    }
+}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLDescriptorSpecifier.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLDescriptorSpecifier.java
index 2208f3a..617b4ed 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLDescriptorSpecifier.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLDescriptorSpecifier.java
@@ -21,10 +21,6 @@ package org.apache.royale.compiler.internal.codegen.mxml.royale;
 
 import java.util.ArrayList;
 
-import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
-import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogEmitterTokens;
-import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
-
 /**
  * @author Erik de Bruin
  */
@@ -118,282 +114,4 @@ public class MXMLDescriptorSpecifier extends MXMLNodeSpecifier
     //---------------------------------
 
     public MXMLDescriptorSpecifier parent;
-
-    //---------------------------------
-    //    currentIndent
-    //---------------------------------
- 
-    private int currentIndent = 0;
-
-    //--------------------------------------------------------------------------
-    //
-    //    Methods
-    //
-    //--------------------------------------------------------------------------
-
-    //---------------------------------
-    //    indent
-    //---------------------------------
-
-    protected String getIndent()
-    {
-        return getIndent(currentIndent);
-    }
-
-    protected String getIndent(int numIndent)
-    {
-        final StringBuilder sb = new StringBuilder();
-        if (parent != null)
-        {
-            sb.append(parent.getIndent());
-        }
-        for (int i = 0; i < numIndent; i++)
-            sb.append(JSRoyaleEmitterTokens.INDENT.getToken());
-        return sb.toString();
-    }
-
-    public void indentPush()
-    {
-        currentIndent++;
-    }
-
-    public void indentPop()
-    {
-        if (currentIndent > 0)
-        {
-            currentIndent--;
-        }
-    }
-
-    @Override
-    protected void writeNewline()
-    {
-        write(ASEmitterTokens.NEW_LINE);
-        write(getIndent(currentIndent));
-    }
-
-    //---------------------------------
-    //    outputEventSpecifier
-    //---------------------------------
-
-    private void outputEventSpecifier(boolean writeNewline)
-    {
-        // number of events
-        int count = 0;
-        for (MXMLEventSpecifier me : eventSpecifiers)
-        {
-            if (me.name != null)
-                count++;
-        }
-        write(count + "");
-
-        for (MXMLEventSpecifier me : eventSpecifiers)
-        {
-            writeDelimiter(writeNewline);
-            write(me.output(writeNewline));
-        }
-    }
-
-    //---------------------------------
-    //    outputPropertySpecifier
-    //---------------------------------
-
-    private String outputPropertySpecifier(boolean writeNewline)
-    {
-        write((isProperty) ? ASEmitterTokens.SINGLE_QUOTE.getToken() : "");
-        write(name);
-        write((isProperty) ? ASEmitterTokens.SINGLE_QUOTE.getToken() : "");
-        writeDelimiter(writeNewline);
-
-        if (isProperty)
-        {
-            if (value != null)
-            {
-                write(ASEmitterTokens.TRUE);
-                writeDelimiter(writeNewline);
-                // need to do other escaping here?
-                // restrict="0-9.\"
-                if (value.endsWith("\\'") && !value.endsWith("\\\\'"))
-                {
-                	value = value.substring(0, value.length() - 1) + "\\'";
-                }
-                write(value);
-            }
-            else
-            {
-                write((hasArray) ? ASEmitterTokens.NULL : ASEmitterTokens.FALSE);
-                writeDelimiter(writeNewline);
-                write(ASEmitterTokens.SQUARE_OPEN);
-                indentPush();
-                writeNewline();
-                output(writeNewline);
-                indentPop();
-                writeNewline();
-                write(ASEmitterTokens.SQUARE_CLOSE);
-            }
-
-            if (parent != null)
-                writeDelimiter(writeNewline);
-        }
-        else
-        {
-            for (MXMLDescriptorSpecifier md : propertySpecifiers)
-            {
-                if (md.name != null && md.name.equals("mxmlContent"))
-                {
-                    childrenSpecifier = md;
-                    propertySpecifiers.remove(md);
-                    break;
-                }
-            }
-
-            if (id != null || effectiveId != null)
-            {
-                write(propertySpecifiers.size() + 1 + "");
-                writeDelimiter(writeNewline);
-                String idPropName = (effectiveId != null) ? "_id"
-                        : "id";
-                writeSimpleDescriptor(idPropName, ASEmitterTokens.TRUE.getToken(),
-                        ASEmitterTokens.SINGLE_QUOTE.getToken()
-                                + ((id != null) ? id : effectiveId) + ASEmitterTokens.SINGLE_QUOTE.getToken(),
-                        writeNewline);
-
-                writeDelimiter(writeNewline);
-            }
-            else
-            {
-                write(propertySpecifiers.size() + "");
-                writeDelimiter(writeNewline);
-            }
-
-            output(writeNewline);
-        }
-
-        return sb.toString();
-    }
-
-    //---------------------------------
-    //    outputStyleSpecifier
-    //---------------------------------
-
-    private void outputStyleSpecifier(boolean writeNewline)
-    {
-        // TODO (erikdebruin) not yet implemented in Royale
-
-        write("0");
-        writeDelimiter(writeNewline);
-    }
-
-    //---------------------------------
-    //    output
-    //---------------------------------
-
-    @Override
-    public String output(boolean writeNewline)
-    {
-        if (isTopNode)
-        {
-            int count = 0;
-            for (MXMLDescriptorSpecifier md : propertySpecifiers)
-            {
-                if (md.name != null)
-                    count++;
-            }
-
-            write(count + "");
-            writeNewline(ASEmitterTokens.COMMA);
-        }
-
-        MXMLDescriptorSpecifier model = null; // model goes first
-        MXMLDescriptorSpecifier beads = null; // beads go last
-
-        for (MXMLDescriptorSpecifier md : propertySpecifiers)
-        {
-            if (md.name != null && md.name.equals("model"))
-            {
-                model = md;
-
-                break;
-            }
-        }
-
-        if (model != null)
-        {
-            write(model.outputPropertySpecifier(writeNewline));
-        }
-
-        for (MXMLDescriptorSpecifier md : propertySpecifiers)
-        {
-            if (md.name != null)
-            {
-                if (!md.name.equals("model") && !md.name.equals("beads"))
-                    write(md.outputPropertySpecifier(writeNewline));
-                else if (md.name.equals("beads"))
-                    beads = md;
-            }
-        }
-
-        if (beads != null)
-        {
-            write(beads.outputPropertySpecifier(writeNewline));
-        }
-
-        if (!isProperty)
-        {
-            outputStyleSpecifier(writeNewline);
-
-            // TODO (erikdebruin) not yet implemented in Royale
-            //outputEffectSpecifier(writeNewline);
-
-            outputEventSpecifier(writeNewline);
-
-            if (!isTopNode)
-            {
-                writeDelimiter(writeNewline);
-
-                if (childrenSpecifier == null)
-                    write(ASEmitterTokens.NULL);
-                else
-                    outputChildren(childrenSpecifier, writeNewline);
-            }
-
-            boolean isLastChild = parent != null
-                    && parent.propertySpecifiers.indexOf(this) == parent.propertySpecifiers
-                            .size() - 1;
-
-            if (!isLastChild && !isTopNode)
-                writeDelimiter(writeNewline);
-        }
-
-        return sb.toString();
-    }
-
-    private void outputChildren(MXMLDescriptorSpecifier children, boolean writeNewline)
-    {
-        write(ASEmitterTokens.SQUARE_OPEN.getToken());
-        if(writeNewline)
-        {
-            indentPush();
-            writeNewline();
-        }
-        write(children.output(writeNewline));
-        if(writeNewline)
-        {
-            indentPop();
-            writeNewline();
-        }
-        write(ASEmitterTokens.SQUARE_CLOSE.getToken());
-    }
-
-    public String outputStateDescriptors(boolean writeNewLine)
-    {
-        for (MXMLDescriptorSpecifier md : propertySpecifiers)
-        {
-            write(ASEmitterTokens.SQUARE_OPEN);
-            write(md.output(writeNewLine));
-            write(ASEmitterTokens.SQUARE_CLOSE);
-            writeNewline(ASEmitterTokens.COMMA);
-        }
-        return sb.toString();
-    }
 }
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLEventSpecifier.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLEventSpecifier.java
index 4c0f777..1e9de21 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLEventSpecifier.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLEventSpecifier.java
@@ -22,7 +22,6 @@ package org.apache.royale.compiler.internal.codegen.mxml.royale;
 import java.util.Arrays;
 import java.util.List;
 
-import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
 import org.apache.royale.compiler.tree.mxml.IMXMLEventSpecifierNode;
 
 /**
@@ -48,7 +47,7 @@ public class MXMLEventSpecifier extends MXMLNodeSpecifier
     //
     //--------------------------------------------------------------------------
 
-    static List<String> nameMap = Arrays.asList(
+    public static List<String> nameMap = Arrays.asList(
     		"rollOver",
     		"rollOut",
     		"mouseDown",
@@ -82,21 +81,6 @@ public class MXMLEventSpecifier extends MXMLNodeSpecifier
     //    output
     //---------------------------------
 
-    public String output(boolean writeNewline)
-    {
-        String handler = ASEmitterTokens.THIS.getToken()
-                + ASEmitterTokens.MEMBER_ACCESS.getToken() + eventHandler;
-        if (nameMap.contains(name))
-        	name = name.toLowerCase();
-		else if (name.equals("doubleClick"))
-			name = "dblclick";
-		else if (name.equals("mouseWheel"))
-			name = "wheel";
-        writeSimpleDescriptor(name, null, handler, writeNewline);
-
-        return sb.toString();
-    }
-
     public static String getJSEventName(String name)
     {
     	if (nameMap.contains(name))
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLNodeSpecifier.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLNodeSpecifier.java
index 62d4b6e..df66d69 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLNodeSpecifier.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLNodeSpecifier.java
@@ -19,9 +19,6 @@
 
 package org.apache.royale.compiler.internal.codegen.mxml.royale;
 
-import org.apache.royale.compiler.codegen.IEmitterTokens;
-import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
-
 /**
  * @author Erik de Bruin
  */
@@ -36,20 +33,7 @@ public class MXMLNodeSpecifier
 
     public MXMLNodeSpecifier()
     {
-        sb = new StringBuilder();
     }
-
-    //--------------------------------------------------------------------------
-    //
-    //    Variables
-    //
-    //--------------------------------------------------------------------------
-
-    //---------------------------------
-    //    sb
-    //---------------------------------
-
-    protected StringBuilder sb;
     
     //--------------------------------------------------------------------------
     //
@@ -74,102 +58,4 @@ public class MXMLNodeSpecifier
     //---------------------------------
 
     public boolean valueNeedsQuotes;
-
-    //--------------------------------------------------------------------------
-    //
-    //    Methods
-    //
-    //--------------------------------------------------------------------------
-
-    //---------------------------------
-    //    output
-    //---------------------------------
-
-    public String output(boolean writeNewline)
-    {
-        return "";
-    }
-
-    //---------------------------------
-    //    write
-    //---------------------------------
-
-    protected void write(IEmitterTokens value)
-    {
-        write(value.getToken());
-    }
-
-    protected void write(String value)
-    {
-        sb.append(value);
-    }
-
-    //---------------------------------
-    //    writeDelimiter
-    //---------------------------------
-
-    protected void writeDelimiter(boolean writeNewline)
-    {
-        if (writeNewline)
-            writeNewline(ASEmitterTokens.COMMA);
-        else
-            writeToken(ASEmitterTokens.COMMA);
-    }
-
-    //---------------------------------
-    //    writeNewline
-    //---------------------------------
-
-    protected void writeNewline(IEmitterTokens value)
-    {
-        writeNewline(value.getToken());
-    }
-
-    protected void writeNewline(String value)
-    {
-        write(value);
-        writeNewline();
-    }
-
-    protected void writeNewline()
-    {
-        write(ASEmitterTokens.NEW_LINE);
-    }
-
-    //---------------------------------
-    //    writeSimpleDescriptor
-    //---------------------------------
-
-    protected void writeSimpleDescriptor(String name, String type, String value,
-            boolean writeNewline)
-    {
-        write(ASEmitterTokens.SINGLE_QUOTE);
-        write(name);
-        write(ASEmitterTokens.SINGLE_QUOTE);
-        writeDelimiter(writeNewline);
-
-        if (type != null)
-        {
-            write(type);
-            writeDelimiter(writeNewline);
-        }
-
-        write(value);
-    }
-
-    //---------------------------------
-    //    writeToken
-    //---------------------------------
-
-    protected void writeToken(IEmitterTokens value)
-    {
-        writeToken(value.getToken());
-    }
-
-    protected void writeToken(String value)
-    {
-        write(value);
-        write(ASEmitterTokens.SPACE);
-    }
-
 }
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java
index 85a0032..820d26a 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java
@@ -38,13 +38,13 @@ import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.royale.abc.ABCConstants;
 import org.apache.royale.abc.instructionlist.InstructionList;
 import org.apache.royale.abc.semantics.Instruction;
-import org.apache.royale.abc.semantics.MethodInfo;
 import org.apache.royale.abc.semantics.Name;
 import org.apache.royale.abc.semantics.Namespace;
 import org.apache.royale.abc.semantics.OneOperandInstruction;
+import org.apache.royale.compiler.codegen.ISubEmitter;
 import org.apache.royale.compiler.codegen.as.IASEmitter;
 import org.apache.royale.compiler.codegen.js.IJSEmitter;
-import org.apache.royale.compiler.codegen.js.IMappingEmitter;
+import org.apache.royale.compiler.codegen.mxml.js.IMXMLJSEmitter;
 import org.apache.royale.compiler.codegen.mxml.royale.IMXMLRoyaleEmitter;
 import org.apache.royale.compiler.common.ASModifier;
 import org.apache.royale.compiler.common.DependencyType;
@@ -71,13 +71,13 @@ import org.apache.royale.compiler.internal.codegen.js.JSSessionModel.PropertyNod
 import org.apache.royale.compiler.internal.codegen.js.JSSessionModel.BindableVarInfo;
 import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
 import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
+import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleBasicMXMLDescriptorEmitter;
 import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogDocEmitter;
 import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogEmitterTokens;
 import org.apache.royale.compiler.internal.codegen.js.jx.BindableEmitter;
 import org.apache.royale.compiler.internal.codegen.js.jx.PackageFooterEmitter;
 import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils;
 import org.apache.royale.compiler.internal.codegen.mxml.MXMLEmitter;
-import org.apache.royale.compiler.internal.codegen.mxml.MXMLEmitterTokens;
 import org.apache.royale.compiler.internal.driver.js.royale.JSCSSCompilationSession;
 import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
 import org.apache.royale.compiler.internal.projects.RoyaleProject;
@@ -102,7 +102,6 @@ import org.apache.royale.compiler.tree.metadata.IMetaTagNode;
 import org.apache.royale.compiler.tree.metadata.IMetaTagsNode;
 import org.apache.royale.compiler.tree.mxml.*;
 import org.apache.royale.compiler.units.ICompilationUnit;
-import org.apache.royale.compiler.utils.DefinitionUtils;
 import org.apache.royale.compiler.utils.NativeUtils;
 import org.apache.royale.compiler.visitor.mxml.IMXMLBlockWalker;
 import org.apache.royale.swc.ISWC;
@@ -115,7 +114,7 @@ import com.google.debugging.sourcemap.FilePosition;
  * @author Erik de Bruin
  */
 public class MXMLRoyaleEmitter extends MXMLEmitter implements
-        IMXMLRoyaleEmitter, IMappingEmitter
+        IMXMLRoyaleEmitter, IMXMLJSEmitter
 {
 
 	// the instances in a container
@@ -154,6 +153,8 @@ public class MXMLRoyaleEmitter extends MXMLEmitter implements
     private String interfaceList;
     private boolean emitExports = true;
 
+    private ISubEmitter<MXMLDescriptorSpecifier> mxmlDescriptorEmitter;
+
     /**
      * This keeps track of the entries in our temporary array of
      * DeferredInstanceFromFunction objects that we CG to help with
@@ -179,6 +180,8 @@ public class MXMLRoyaleEmitter extends MXMLEmitter implements
     {
         super(out);
         sourceMapMappings = new ArrayList<SourceMapMapping>();
+
+        mxmlDescriptorEmitter = new JSRoyaleBasicMXMLDescriptorEmitter(this);
     }
 
     @Override
@@ -840,6 +843,7 @@ public class MXMLRoyaleEmitter extends MXMLEmitter implements
 
         descriptorTree = new ArrayList<MXMLDescriptorSpecifier>();
         propertiesTree = new MXMLDescriptorSpecifier();
+        propertiesTree.name = node.getQualifiedName();
 
         events = new ArrayList<MXMLEventSpecifier>();
         instances = new ArrayList<MXMLDescriptorSpecifier>();
@@ -1112,8 +1116,15 @@ public class MXMLRoyaleEmitter extends MXMLEmitter implements
 	        writeNewline(" * @type {Array}");
 	        writeNewline(" */");
 	        writeNewline("this.mxmlsd = " + ASEmitterTokens.SQUARE_OPEN.getToken());
-	        indentPush();
-	        write(root.outputStateDescriptors(false));
+            indentPush();
+            
+            for (MXMLDescriptorSpecifier md : root.propertySpecifiers)
+            {
+                write(ASEmitterTokens.SQUARE_OPEN);
+                mxmlDescriptorEmitter.emit(md);
+                write(ASEmitterTokens.SQUARE_CLOSE);
+                writeNewline(ASEmitterTokens.COMMA);
+            }
 	        write("null");
 	        write(ASEmitterTokens.SQUARE_CLOSE);
 	        indentPop();
@@ -1141,11 +1152,7 @@ public class MXMLRoyaleEmitter extends MXMLEmitter implements
 
             MXMLDescriptorSpecifier root = propertiesTree;
             root.isTopNode = true;
-            for(int i = 0; i < getCurrentIndent(); i++)
-            {
-                root.indentPush();
-            }
-            write(root.output(true));
+            mxmlDescriptorEmitter.emit(root);
             indentPop();
             writeNewline();
 
@@ -2205,11 +2212,7 @@ public class MXMLRoyaleEmitter extends MXMLEmitter implements
             indentPush();
             writeNewline("var data = [");
 
-            for(int i = 0; i < getCurrentIndent(); i++)
-            {
-                root.indentPush();
-            }
-            write(root.output(true));
+            mxmlDescriptorEmitter.emit(root);
             indentPop();
             writeNewline();