You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by ah...@apache.org on 2019/11/05 21:53:26 UTC

[royale-compiler] 02/03: static initializers that reference external classes are now generated as get/set to reduce issues with dependency order

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

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

commit e473fc65acc2266f06fa8e7f39746de1bcaedada
Author: Alex Harui <ah...@apache.org>
AuthorDate: Tue Nov 5 13:14:11 2019 -0800

    static initializers that reference external classes are now generated as get/set to reduce issues with dependency order
---
 .../internal/codegen/js/jx/FieldEmitter.java       | 226 ++++++++++-
 .../codegen/mxml/royale/TestRoyaleMXMLScript.java  | 416 +++++++++++++++++++++
 2 files changed, 622 insertions(+), 20 deletions(-)

diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FieldEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FieldEmitter.java
index 1271863..6cf5dd2 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FieldEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FieldEmitter.java
@@ -25,12 +25,14 @@ import org.apache.royale.compiler.codegen.js.goog.IJSGoogDocEmitter;
 import org.apache.royale.compiler.common.ASModifier;
 import org.apache.royale.compiler.common.ModifiersSet;
 import org.apache.royale.compiler.constants.IASKeywordConstants;
+import org.apache.royale.compiler.constants.IASLanguageConstants;
 import org.apache.royale.compiler.definitions.*;
 import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
 import org.apache.royale.compiler.internal.codegen.js.JSEmitterTokens;
 import org.apache.royale.compiler.internal.codegen.js.JSSessionModel.BindableVarInfo;
 import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
 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.utils.EmitterUtils;
 import org.apache.royale.compiler.internal.definitions.FunctionDefinition;
 import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
@@ -46,6 +48,7 @@ import org.apache.royale.compiler.tree.as.INamespaceDecorationNode;
 import org.apache.royale.compiler.tree.as.IVariableNode;
 import org.apache.royale.compiler.tree.metadata.IMetaTagNode;
 import org.apache.royale.compiler.tree.metadata.IMetaTagsNode;
+import org.apache.royale.compiler.utils.NativeUtils;
 
 /**
  * Static or member variables of a class. For local variables in a function, see
@@ -61,10 +64,62 @@ public class FieldEmitter extends JSSubEmitter implements
 
     public boolean hasComplexStaticInitializers = false;
     
+    private boolean isComplex(IExpressionNode vnode, IDefinition definition)
+    {
+    	if (EmitterUtils.isScalar(vnode))
+    		return false;
+    	
+    	IClassDefinition cdef = (IClassDefinition)definition;
+    	
+    	// walk the tree of nodes looking for IdentifierNodes
+    	// and see if they resolve to external dependencies
+    	return isExternalReference(vnode, cdef);
+    }
+    
+    private boolean isExternalReference(IExpressionNode vnode, IClassDefinition cdef)
+    {
+    	if (vnode.getNodeID() == ASTNodeID.IdentifierID)
+    	{
+    		IDefinition def = vnode.resolve(getProject());
+    		if (def == null)  // saw this for a package reference (org in org.apache)
+    			return false;
+    		String qname = def.getQualifiedName();
+    		if (NativeUtils.isJSNative(qname))
+    			return false;
+    		if (def instanceof IClassDefinition)
+    			return !(qname.contentEquals(cdef.getQualifiedName()));
+    		def = def.getParent();
+    		if (def != null)
+    		{
+    			qname = def.getQualifiedName();
+    			return !(qname.contentEquals(cdef.getQualifiedName()));
+    		}
+    	}
+    	int n = vnode.getChildCount();
+    	for (int i = 0; i < n; i++)
+    	{
+    		IASNode childNode = vnode.getChild(i);
+    		if (childNode instanceof IExpressionNode)
+    		{
+    			if (isExternalReference((IExpressionNode)childNode, cdef))
+    				return true;
+    		}
+    	}
+    	return false;
+    }
+    
     @Override
     public void emit(IVariableNode node)
     {
+        IExpressionNode vnode = node.getAssignedValueNode();;
+        boolean isBindable = (node.getNodeID() == ASTNodeID.BindableVariableID && !node.isConst());
+        IDefinition ndef = node.getDefinition();
         IDefinition definition = EmitterUtils.getClassDefinition(node);
+        if (definition == null && ndef != null)
+        {
+        	definition = ndef.getParent();
+        }
+        boolean isComplexInitializedStatic = vnode != null && ndef.isStatic() && !isBindable && isComplex(vnode, definition);
         JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter();
         IDefinition def = null;
         IExpressionNode enode = node.getVariableTypeNode();//getAssignedValueNode();
@@ -74,12 +129,11 @@ public class FieldEmitter extends JSSubEmitter implements
         }
 
         // TODO (mschmalle)
-        if (getEmitter().getDocEmitter() instanceof IJSGoogDocEmitter)
+        if (getEmitter().getDocEmitter() instanceof IJSGoogDocEmitter && !isComplexInitializedStatic)
         {
             ((IJSGoogDocEmitter) getEmitter().getDocEmitter()).emitFieldDoc(node, def, getProject());
         }
 
-        IDefinition ndef = node.getDefinition();
 
         String className = null;
         String root = "";
@@ -105,35 +159,149 @@ public class FieldEmitter extends JSSubEmitter implements
 
             startMapping(node.getNameExpressionNode());
             className = getEmitter().formatQualifiedName(definition.getQualifiedName());
-            write(className
-                    + ASEmitterTokens.MEMBER_ACCESS.getToken() + root);
-            String qname = node.getName();
-            IDefinition nodeDef = node.getDefinition();
-            if (nodeDef != null && !nodeDef.isStatic() && nodeDef.isPrivate() && getProject().getAllowPrivateNameConflicts())
-        			qname = getEmitter().formatPrivateName(nodeDef.getParent().getQualifiedName(), qname);
-    
-            if (EmitterUtils.isCustomNamespace(node.getNamespace())) {
-                INamespaceDecorationNode ns = ((VariableNode) node).getNamespaceNode();
-                INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(getProject());
-                fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
-                String s = nsDef.getURI();
-                write(JSRoyaleEmitter.formatNamespacedProperty(s, qname, false));
+            if (isComplexInitializedStatic)
+            {
+	            write(className
+	                    + ASEmitterTokens.MEMBER_ACCESS.getToken() + JSRoyaleEmitterTokens.GETTER_PREFIX.getToken());
+	            writeFieldName(node, fjs);
+	            endMapping(node.getNameExpressionNode());
+                write(ASEmitterTokens.SPACE);
+                writeToken(ASEmitterTokens.EQUAL);
+                write(ASEmitterTokens.FUNCTION);
+                write(ASEmitterTokens.PAREN_OPEN);
+                writeToken(ASEmitterTokens.PAREN_CLOSE);
+                writeNewline(ASEmitterTokens.BLOCK_OPEN, true);
+                String vnodeString = getEmitter().stringifyNode(vnode);
+                writeToken(ASEmitterTokens.VAR);
+                writeToken("value");
+                writeToken(ASEmitterTokens.EQUAL);
+                write(vnodeString);
+                writeNewline(ASEmitterTokens.SEMICOLON);
+                write(IASLanguageConstants.Object);
+                write(ASEmitterTokens.MEMBER_ACCESS);
+                write(JSEmitterTokens.DEFINE_PROPERTY);
+                write(ASEmitterTokens.PAREN_OPEN);
+                write(className);
+                writeToken(ASEmitterTokens.COMMA);
+                write(ASEmitterTokens.SINGLE_QUOTE);
+	            writeFieldName(node, fjs);
+                write(ASEmitterTokens.SINGLE_QUOTE);
+                writeToken(ASEmitterTokens.COMMA);
+                if (node.isConst())
+                	write("{ value: value, writable: false }");
+                else
+                	write("{ value: value, writable: true }");
+                write(ASEmitterTokens.PAREN_CLOSE);
+                writeNewline(ASEmitterTokens.SEMICOLON);
+                writeToken(ASEmitterTokens.RETURN);
+                write("value");
+                indentPop();
+                writeNewline(ASEmitterTokens.SEMICOLON);
+                write(ASEmitterTokens.BLOCK_CLOSE);
+                writeNewline(ASEmitterTokens.SEMICOLON);
+                if (!node.isConst())
+                {
+		            write(className
+		                    + ASEmitterTokens.MEMBER_ACCESS.getToken() + JSRoyaleEmitterTokens.SETTER_PREFIX.getToken());
+		            writeFieldName(node, fjs);
+	                write(ASEmitterTokens.SPACE);
+	                writeToken(ASEmitterTokens.EQUAL);
+	                write(ASEmitterTokens.FUNCTION);
+	                write(ASEmitterTokens.PAREN_OPEN);
+	                write("value");
+	                writeToken(ASEmitterTokens.PAREN_CLOSE);
+	                writeNewline(ASEmitterTokens.BLOCK_OPEN, true);
+	                write(IASLanguageConstants.Object);
+	                write(ASEmitterTokens.MEMBER_ACCESS);
+	                write(JSEmitterTokens.DEFINE_PROPERTY);
+	                write(ASEmitterTokens.PAREN_OPEN);
+	                write(className);
+	                writeToken(ASEmitterTokens.COMMA);
+	                write(ASEmitterTokens.SINGLE_QUOTE);
+		            writeFieldName(node, fjs);
+	                write(ASEmitterTokens.SINGLE_QUOTE);
+	                writeToken(ASEmitterTokens.COMMA);
+	                write("{ value: value, writable: true }");
+	                write(ASEmitterTokens.PAREN_CLOSE);
+	                indentPop();
+	                writeNewline(ASEmitterTokens.SEMICOLON);
+	                write(ASEmitterTokens.BLOCK_CLOSE);
+	                writeNewline(ASEmitterTokens.SEMICOLON);
+                }
+                write(IASLanguageConstants.Object);
+                write(ASEmitterTokens.MEMBER_ACCESS);
+                write(JSEmitterTokens.DEFINE_PROPERTIES);
+                write(ASEmitterTokens.PAREN_OPEN);
+                write(className);
+                writeToken(ASEmitterTokens.COMMA);
+                write("/** @lends {" + className
+                        + "} */ ");
+                writeNewline(ASEmitterTokens.BLOCK_OPEN);
+                // TODO (mschmalle)
+                if (getEmitter().getDocEmitter() instanceof IJSGoogDocEmitter)
+                {
+                    ((IJSGoogDocEmitter) getEmitter().getDocEmitter()).emitFieldDoc(node, def, getProject());
+                }
+	            writeFieldName(node, fjs);
+                writeToken(ASEmitterTokens.COLON);
+                writeNewline(ASEmitterTokens.BLOCK_OPEN, true);
+                write(ASEmitterTokens.GET);
+                write(ASEmitterTokens.COLON);
+                write(ASEmitterTokens.SPACE);
+                write(className);
+                write(ASEmitterTokens.MEMBER_ACCESS);
+                write(JSRoyaleEmitterTokens.GETTER_PREFIX);
+	            writeFieldName(node, fjs);
+	            if (!node.isConst())
+	            {
+	            	writeNewline(ASEmitterTokens.COMMA);
+	                write(ASEmitterTokens.SET);
+	                write(ASEmitterTokens.COLON);
+	                write(ASEmitterTokens.SPACE);
+	                write(className);
+	                write(ASEmitterTokens.MEMBER_ACCESS);
+	                write(JSRoyaleEmitterTokens.SETTER_PREFIX);
+		            writeFieldName(node, fjs);
+	            }
+            	writeNewline(ASEmitterTokens.COMMA);
+                write("configurable: true");
+                write(ASEmitterTokens.BLOCK_CLOSE);
+                write(ASEmitterTokens.BLOCK_CLOSE);
+                write(ASEmitterTokens.PAREN_CLOSE);
+                indentPop();
+            }
+            else
+            {
+	            write(className
+	                    + ASEmitterTokens.MEMBER_ACCESS.getToken() + root);
+	            String qname = node.getName();
+	            IDefinition nodeDef = node.getDefinition();
+	            if (nodeDef != null && !nodeDef.isStatic() && nodeDef.isPrivate() && getProject().getAllowPrivateNameConflicts())
+	        			qname = getEmitter().formatPrivateName(nodeDef.getParent().getQualifiedName(), qname);
+	    
+	            if (EmitterUtils.isCustomNamespace(node.getNamespace())) {
+	                INamespaceDecorationNode ns = ((VariableNode) node).getNamespaceNode();
+	                INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(getProject());
+	                fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
+	                String s = nsDef.getURI();
+	                write(JSRoyaleEmitter.formatNamespacedProperty(s, qname, false));
+	            }
+	            else write(qname);
+	            endMapping(node.getNameExpressionNode());
             }
-            else write(qname);
-            endMapping(node.getNameExpressionNode());
         }
 
-        if (node.getNodeID() == ASTNodeID.BindableVariableID && !node.isConst())
+        if (isBindable)
         {
             // add an underscore to convert this var to be the
             // backing var for the get/set pair that will be generated later.
             write("_");
         }
-        IExpressionNode vnode = node.getAssignedValueNode();
-        if (vnode != null)
+        if (vnode != null && !isComplexInitializedStatic)
         {
         	getModel().inStaticInitializer = ndef.isStatic();
             String vnodeString = getEmitter().stringifyNode(vnode);
+            /*
             if (ndef.isStatic() && vnode instanceof FunctionCallNode)
             {
                 FunctionCallNode fcn = (FunctionCallNode)vnode;
@@ -169,6 +337,7 @@ public class FieldEmitter extends JSSubEmitter implements
                     }
             	}
             }
+            */
         	getModel().inStaticInitializer = false;
         	if ((ndef.isStatic() && !EmitterUtils.needsStaticInitializer(vnodeString, className)) ||
         			(!ndef.isStatic() && EmitterUtils.isScalar(vnode)) ||
@@ -297,6 +466,23 @@ public class FieldEmitter extends JSSubEmitter implements
             }
         }
     }
+    
+    private void writeFieldName(IVariableNode node, JSRoyaleEmitter fjs)
+    {
+        String qname = node.getName();
+        IDefinition nodeDef = node.getDefinition();
+        if (nodeDef != null && !nodeDef.isStatic() && nodeDef.isPrivate() && getProject().getAllowPrivateNameConflicts())
+    			qname = getEmitter().formatPrivateName(nodeDef.getParent().getQualifiedName(), qname);
+
+        if (EmitterUtils.isCustomNamespace(node.getNamespace())) {
+            INamespaceDecorationNode ns = ((VariableNode) node).getNamespaceNode();
+            INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(getProject());
+            fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
+            String s = nsDef.getURI();
+            write(JSRoyaleEmitter.formatNamespacedProperty(s, qname, false));
+        }
+        else write(qname);
+    }
 
     public boolean emitFieldInitializer(IVariableNode node)
     {
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/royale/TestRoyaleMXMLScript.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/royale/TestRoyaleMXMLScript.java
index 02b9bd9..eb5713b 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/royale/TestRoyaleMXMLScript.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/royale/TestRoyaleMXMLScript.java
@@ -332,6 +332,422 @@ public class TestRoyaleMXMLScript extends RoyaleTestBase
     }
     
     @Test
+    public void testComplexExpressionStaticInitializersInScript()
+    {
+        String code = "" + "<fx:Script><![CDATA["
+                + "    import org.apache.royale.events.CloseEvent;"
+                + "    public static var foo:String = CloseEvent.CLOSE;"
+                + "]]></fx:Script>";
+
+        IMXMLScriptNode node = (IMXMLScriptNode) getNode(code,
+                IMXMLScriptNode.class, RoyaleTestBase.WRAP_LEVEL_DOCUMENT);
+
+        IMXMLDocumentNode dnode = (IMXMLDocumentNode) node
+        	.getAncestorOfType(IMXMLDocumentNode.class);
+        ((JSRoyaleEmitter)(mxmlBlockWalker.getASEmitter())).getModel().setCurrentClass(dnode.getDefinition());
+        mxmlBlockWalker.visitDocument(dnode);
+        String appName = dnode.getQualifiedName();
+        String outTemplate = "/**\n" +
+        		" * AppName\n" +
+        		" *\n" +
+        		" * @fileoverview\n" +
+        		" *\n" +
+        		" * @suppress {checkTypes|accessControls}\n" +
+        		" */\n" +
+        		"\n" +
+        		"goog.provide('AppName');\n" +
+        		"\n" +
+        		"goog.require('org.apache.royale.core.Application');\n" +
+        		"goog.require('org.apache.royale.events.CloseEvent');\n" +
+        		"\n" +
+        		"\n" +
+        		"\n" +
+        		"/**\n" +
+        		" * @constructor\n" +
+        		" * @extends {org.apache.royale.core.Application}\n" +
+        		" */\n" +
+        		"AppName = function() {\n" +
+        		"  AppName.base(this, 'constructor');\n" +
+        		"  \n" +
+        		"  /**\n" +
+        		"   * @private\n" +
+        		"   * @type {Array}\n" +
+        		"   */\n" +
+        		"  this.mxmldd;\n" +
+        		"  \n" +
+        		"  /**\n" +
+        		"   * @private\n" +
+        		"   * @type {Array}\n" +
+        		"   */\n" +
+        		"  this.mxmldp;\n" +
+        		"};\n" +
+        		"goog.inherits(AppName, org.apache.royale.core.Application);\n" +
+          		"\n" +
+        		"\n" +
+        		"/**\n" +
+        		" * Prevent renaming of class. Needed for reflection.\n" +
+        		" */\n" +
+        		"goog.exportSymbol('AppName', AppName);\n" +
+        		"\n" +
+        		"\n" +
+				"\n" +
+				"AppName.get__foo = function() {\n" +
+				"  var value = org.apache.royale.events.CloseEvent.CLOSE;\n" +
+				"  Object.defineProperty(AppName, 'foo', { value: value, writable: true });\n" +
+				"  return value;\n" +
+				"};\n" +
+				"AppName.set__foo = function(value) {\n" +
+				"  Object.defineProperty(AppName, 'foo', { value: value, writable: true });\n" +
+				"};\n" +
+				"Object.defineProperties(AppName, /** @lends {AppName} */ {\n" +
+				"/**\n" +
+				" * @export\n" +
+				" * @type {string}\n" +
+				" */\n" +
+				"foo: {\n" +
+				"  get: AppName.get__foo,\n" +
+				"  set: AppName.set__foo,\n" +
+				"  configurable: true}});\n" +
+				"\n" +
+				"\n" +
+        		"/**\n" +
+        		" * Metadata\n" +
+        		" *\n" +
+        		" * @type {Object.<string, Array.<Object>>}\n" +
+        		" */\n" +
+        		"AppName.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'AppName', qName: 'AppName', kind: 'class'  }] };\n" +
+          		"\n" +
+        		"\n" +
+        		"\n" +
+        		"/**\n" +
+        		" * Reflection\n" +
+        		" *\n" +
+        		" * @return {Object.<string, Function>}\n" +
+        		" */\n" +
+        		"AppName.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+				"  return {\n" +
+			    "    variables: function () {\n" +
+        		"      return {\n" +
+        		"        '|foo': { type: 'String', get_set: function (/** * */ v) {return v !== undefined ? AppName.foo = v : AppName.foo;}}\n" +
+        		"      };\n" +
+        		"    },\n" +
+				"    methods: function () {\n" +
+				"      return {\n" +
+				"        'AppName': { type: '', declaredBy: 'AppName'}\n" +
+				"      };\n" +
+				"    }\n" +
+				"  };\n" +
+				"};\n" +
+        		"\n" +
+        		"\n" ;
+        	
+        assertOutWithMetadata(outTemplate.replaceAll("AppName", appName));
+    }
+    
+    @Test
+    public void testSimpleStaticInitializersInScript()
+    {
+        String code = "" + "<fx:Script><![CDATA["
+                + "    public static var foo:String = 'foo';"
+                + "]]></fx:Script>";
+
+        IMXMLScriptNode node = (IMXMLScriptNode) getNode(code,
+                IMXMLScriptNode.class, RoyaleTestBase.WRAP_LEVEL_DOCUMENT);
+
+        IMXMLDocumentNode dnode = (IMXMLDocumentNode) node
+        	.getAncestorOfType(IMXMLDocumentNode.class);
+        ((JSRoyaleEmitter)(mxmlBlockWalker.getASEmitter())).getModel().setCurrentClass(dnode.getDefinition());
+        mxmlBlockWalker.visitDocument(dnode);
+        String appName = dnode.getQualifiedName();
+        String outTemplate = "/**\n" +
+        		" * AppName\n" +
+        		" *\n" +
+        		" * @fileoverview\n" +
+        		" *\n" +
+        		" * @suppress {checkTypes|accessControls}\n" +
+        		" */\n" +
+        		"\n" +
+        		"goog.provide('AppName');\n" +
+        		"\n" +
+        		"goog.require('org.apache.royale.core.Application');\n" +
+        		"\n" +
+        		"\n" +
+        		"\n" +
+        		"/**\n" +
+        		" * @constructor\n" +
+        		" * @extends {org.apache.royale.core.Application}\n" +
+        		" */\n" +
+        		"AppName = function() {\n" +
+        		"  AppName.base(this, 'constructor');\n" +
+        		"  \n" +
+        		"  /**\n" +
+        		"   * @private\n" +
+        		"   * @type {Array}\n" +
+        		"   */\n" +
+        		"  this.mxmldd;\n" +
+        		"  \n" +
+        		"  /**\n" +
+        		"   * @private\n" +
+        		"   * @type {Array}\n" +
+        		"   */\n" +
+        		"  this.mxmldp;\n" +
+        		"};\n" +
+        		"goog.inherits(AppName, org.apache.royale.core.Application);\n" +
+          		"\n" +
+        		"\n" +
+        		"/**\n" +
+        		" * Prevent renaming of class. Needed for reflection.\n" +
+        		" */\n" +
+        		"goog.exportSymbol('AppName', AppName);\n" +
+        		"\n" +
+        		"\n" +
+				"\n" +
+				"/**\n" +
+				" * @export\n" +
+				" * @type {string}\n" +
+				" */\n" +
+				"AppName.foo = 'foo';\n" +
+				"\n" +
+				"\n" +
+        		"/**\n" +
+        		" * Metadata\n" +
+        		" *\n" +
+        		" * @type {Object.<string, Array.<Object>>}\n" +
+        		" */\n" +
+        		"AppName.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'AppName', qName: 'AppName', kind: 'class'  }] };\n" +
+          		"\n" +
+        		"\n" +
+        		"\n" +
+        		"/**\n" +
+        		" * Reflection\n" +
+        		" *\n" +
+        		" * @return {Object.<string, Function>}\n" +
+        		" */\n" +
+        		"AppName.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+				"  return {\n" +
+				"    variables: function () {\n" +
+				"      return {\n" +
+				"        '|foo': { type: 'String', get_set: function (/** * */ v) {return v !== undefined ? AppName.foo = v : AppName.foo;}}\n" +
+				"      };\n" +
+				"    },\n" +
+				"    methods: function () {\n" +
+				"      return {\n" +
+				"        'AppName': { type: '', declaredBy: 'AppName'}\n" +
+				"      };\n" +
+				"    }\n" +
+				"  };\n" +
+				"};\n" +
+        		"\n" +
+        		"\n" ;
+        	
+        assertOutWithMetadata(outTemplate.replaceAll("AppName", appName));
+    }
+    
+    @Test
+    public void testComplexStaticInitializersInScript()
+    {
+        String code = "" + "<fx:Script><![CDATA["
+                + "    public static var foo:Array = ['foo'];"
+                + "]]></fx:Script>";
+
+        IMXMLScriptNode node = (IMXMLScriptNode) getNode(code,
+                IMXMLScriptNode.class, RoyaleTestBase.WRAP_LEVEL_DOCUMENT);
+
+        IMXMLDocumentNode dnode = (IMXMLDocumentNode) node
+        	.getAncestorOfType(IMXMLDocumentNode.class);
+        ((JSRoyaleEmitter)(mxmlBlockWalker.getASEmitter())).getModel().setCurrentClass(dnode.getDefinition());
+        mxmlBlockWalker.visitDocument(dnode);
+        String appName = dnode.getQualifiedName();
+        String outTemplate = "/**\n" +
+        		" * AppName\n" +
+        		" *\n" +
+        		" * @fileoverview\n" +
+        		" *\n" +
+        		" * @suppress {checkTypes|accessControls}\n" +
+        		" */\n" +
+        		"\n" +
+        		"goog.provide('AppName');\n" +
+        		"\n" +
+        		"goog.require('org.apache.royale.core.Application');\n" +
+        		"\n" +
+        		"\n" +
+        		"\n" +
+        		"/**\n" +
+        		" * @constructor\n" +
+        		" * @extends {org.apache.royale.core.Application}\n" +
+        		" */\n" +
+        		"AppName = function() {\n" +
+        		"  AppName.base(this, 'constructor');\n" +
+        		"  \n" +
+        		"  /**\n" +
+        		"   * @private\n" +
+        		"   * @type {Array}\n" +
+        		"   */\n" +
+        		"  this.mxmldd;\n" +
+        		"  \n" +
+        		"  /**\n" +
+        		"   * @private\n" +
+        		"   * @type {Array}\n" +
+        		"   */\n" +
+        		"  this.mxmldp;\n" +
+        		"};\n" +
+        		"goog.inherits(AppName, org.apache.royale.core.Application);\n" +
+          		"\n" +
+        		"\n" +
+        		"/**\n" +
+        		" * Prevent renaming of class. Needed for reflection.\n" +
+        		" */\n" +
+        		"goog.exportSymbol('AppName', AppName);\n" +
+        		"\n" +
+        		"\n" +
+				"\n" +
+				"/**\n" +
+				" * @export\n" +
+				" * @type {Array}\n" +
+				" */\n" +
+				"AppName.foo = ['foo'];\n" +
+				"\n" +
+				"\n" +
+        		"/**\n" +
+        		" * Metadata\n" +
+        		" *\n" +
+        		" * @type {Object.<string, Array.<Object>>}\n" +
+        		" */\n" +
+        		"AppName.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'AppName', qName: 'AppName', kind: 'class'  }] };\n" +
+          		"\n" +
+        		"\n" +
+        		"\n" +
+        		"/**\n" +
+        		" * Reflection\n" +
+        		" *\n" +
+        		" * @return {Object.<string, Function>}\n" +
+        		" */\n" +
+        		"AppName.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+				"  return {\n" +
+				"    variables: function () {\n" +
+				"      return {\n" +
+				"        '|foo': { type: 'Array', get_set: function (/** * */ v) {return v !== undefined ? AppName.foo = v : AppName.foo;}}\n" +
+				"      };\n" +
+				"    },\n" +
+				"    methods: function () {\n" +
+				"      return {\n" +
+				"        'AppName': { type: '', declaredBy: 'AppName'}\n" +
+				"      };\n" +
+				"    }\n" +
+				"  };\n" +
+				"};\n" +
+        		"\n" +
+        		"\n" ;
+        	
+        assertOutWithMetadata(outTemplate.replaceAll("AppName", appName));
+    }
+        
+    @Test
+    public void testConstComplexExpressionStaticInitializersInScript()
+    {
+        String code = "" + "<fx:Script><![CDATA["
+        		+ "    import org.apache.royale.events.CloseEvent;"
+                + "    public static const foo:String = CloseEvent.CLOSE;"
+                + "]]></fx:Script>";
+
+        IMXMLScriptNode node = (IMXMLScriptNode) getNode(code,
+                IMXMLScriptNode.class, RoyaleTestBase.WRAP_LEVEL_DOCUMENT);
+
+        IMXMLDocumentNode dnode = (IMXMLDocumentNode) node
+        	.getAncestorOfType(IMXMLDocumentNode.class);
+        ((JSRoyaleEmitter)(mxmlBlockWalker.getASEmitter())).getModel().setCurrentClass(dnode.getDefinition());
+        mxmlBlockWalker.visitDocument(dnode);
+        String appName = dnode.getQualifiedName();
+        String outTemplate = "/**\n" +
+        		" * AppName\n" +
+        		" *\n" +
+        		" * @fileoverview\n" +
+        		" *\n" +
+        		" * @suppress {checkTypes|accessControls}\n" +
+        		" */\n" +
+        		"\n" +
+        		"goog.provide('AppName');\n" +
+        		"\n" +
+        		"goog.require('org.apache.royale.core.Application');\n" +
+        		"goog.require('org.apache.royale.events.CloseEvent');\n" +
+        		"\n" +
+        		"\n" +
+        		"\n" +
+        		"/**\n" +
+        		" * @constructor\n" +
+        		" * @extends {org.apache.royale.core.Application}\n" +
+        		" */\n" +
+        		"AppName = function() {\n" +
+        		"  AppName.base(this, 'constructor');\n" +
+        		"  \n" +
+        		"  /**\n" +
+        		"   * @private\n" +
+        		"   * @type {Array}\n" +
+        		"   */\n" +
+        		"  this.mxmldd;\n" +
+        		"  \n" +
+        		"  /**\n" +
+        		"   * @private\n" +
+        		"   * @type {Array}\n" +
+        		"   */\n" +
+        		"  this.mxmldp;\n" +
+        		"};\n" +
+        		"goog.inherits(AppName, org.apache.royale.core.Application);\n" +
+          		"\n" +
+        		"\n" +
+        		"/**\n" +
+        		" * Prevent renaming of class. Needed for reflection.\n" +
+        		" */\n" +
+        		"goog.exportSymbol('AppName', AppName);\n" +
+        		"\n" +
+        		"\n" +
+				"\n" +
+				"AppName.get__foo = function() {\n" +
+				"  var value = org.apache.royale.events.CloseEvent.CLOSE;\n" +
+				"  Object.defineProperty(AppName, 'foo', { value: value, writable: false });\n" +
+				"  return value;\n" +
+				"};\n" +
+				"Object.defineProperties(AppName, /** @lends {AppName} */ {\n" +
+				"/**\n" +
+				" * @export\n" +
+				" * @const\n" +
+				" * @type {string}\n" +
+				" */\n" +
+				"foo: {\n" +
+				"  get: AppName.get__foo,\n" +
+				"  configurable: true}});\n" +
+				"\n" +
+				"\n" +
+        		"/**\n" +
+        		" * Metadata\n" +
+        		" *\n" +
+        		" * @type {Object.<string, Array.<Object>>}\n" +
+        		" */\n" +
+        		"AppName.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'AppName', qName: 'AppName', kind: 'class'  }] };\n" +
+          		"\n" +
+        		"\n" +
+        		"\n" +
+        		"/**\n" +
+        		" * Reflection\n" +
+        		" *\n" +
+        		" * @return {Object.<string, Function>}\n" +
+        		" */\n" +
+        		"AppName.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+				"  return {\n" +
+				"    methods: function () {\n" +
+				"      return {\n" +
+				"        'AppName': { type: '', declaredBy: 'AppName'}\n" +
+				"      };\n" +
+				"    }\n" +
+				"  };\n" +
+				"};\n" +
+        		"\n" +
+        		"\n" ;
+        	
+        assertOutWithMetadata(outTemplate.replaceAll("AppName", appName));
+    }
+    
+    @Test
     public void testComplexCustomNamespaceInitializersInScript()
     {
         String code = "" + "<fx:Script><![CDATA["